diff --git a/spring-data-document-core/src/main/java/org/springframework/data/document/web/bind/annotation/support/HandlerMethodInvoker.java b/spring-data-document-core/src/main/java/org/springframework/data/document/web/bind/annotation/support/HandlerMethodInvoker.java deleted file mode 100644 index 0e6e4119a..000000000 --- a/spring-data-document-core/src/main/java/org/springframework/data/document/web/bind/annotation/support/HandlerMethodInvoker.java +++ /dev/null @@ -1,821 +0,0 @@ -/* - * Copyright 2002-2010 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - - -package org.springframework.data.document.web.bind.annotation.support; - -import java.lang.annotation.Annotation; -import java.lang.reflect.*; -import java.util.*; - -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; -import org.springframework.beans.BeanUtils; -import org.springframework.beans.factory.annotation.Value; -import org.springframework.core.*; -import org.springframework.core.annotation.AnnotationUtils; -import org.springframework.http.*; -import org.springframework.http.converter.HttpMessageConverter; -import org.springframework.ui.ExtendedModelMap; -import org.springframework.ui.Model; -import org.springframework.util.*; -import org.springframework.validation.BindException; -import org.springframework.validation.BindingResult; -import org.springframework.validation.Errors; -import org.springframework.web.HttpMediaTypeNotSupportedException; -import org.springframework.web.bind.WebDataBinder; -import org.springframework.web.bind.annotation.*; -import org.springframework.web.bind.annotation.support.HandlerMethodInvocationException; -import org.springframework.web.bind.annotation.support.HandlerMethodResolver; -import org.springframework.web.bind.support.*; -import org.springframework.web.context.request.NativeWebRequest; -import org.springframework.web.context.request.WebRequest; -import org.springframework.web.multipart.MultipartFile; -import org.springframework.web.multipart.MultipartRequest; - -/** - * Support class for invoking an annotated handler method. Operates on the introspection results of a {@link - * HandlerMethodResolver} for a specific handler type. - *

- *

Used by {@link org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter} and {@link - * org.springframework.web.portlet.mvc.annotation.AnnotationMethodHandlerAdapter}. - * - * @author Juergen Hoeller - * @author Arjen Poutsma - * @see #invokeHandlerMethod - * @since 2.5.2 - */ -public class HandlerMethodInvoker { - - private static final String MODEL_KEY_PREFIX_STALE = SessionAttributeStore.class.getName() + ".STALE."; - - /** - * We'll create a lot of these objects, so we don't want a new logger every time. - */ - private static final Log logger = LogFactory.getLog(HandlerMethodInvoker.class); - - private final HandlerMethodResolver methodResolver; - - private final WebBindingInitializer bindingInitializer; - - private final SessionAttributeStore sessionAttributeStore; - - private final ParameterNameDiscoverer parameterNameDiscoverer; - - private final WebArgumentResolver[] customArgumentResolvers; - - private final HttpMessageConverter[] messageConverters; - - private final SimpleSessionStatus sessionStatus = new SimpleSessionStatus(); - - - public HandlerMethodInvoker(HandlerMethodResolver methodResolver) { - this(methodResolver, null); - } - - public HandlerMethodInvoker(HandlerMethodResolver methodResolver, WebBindingInitializer bindingInitializer) { - this(methodResolver, bindingInitializer, new DefaultSessionAttributeStore(), null, null, null); - } - - public HandlerMethodInvoker(HandlerMethodResolver methodResolver, WebBindingInitializer bindingInitializer, - SessionAttributeStore sessionAttributeStore, ParameterNameDiscoverer parameterNameDiscoverer, - WebArgumentResolver[] customArgumentResolvers, HttpMessageConverter[] messageConverters) { - - this.methodResolver = methodResolver; - this.bindingInitializer = bindingInitializer; - this.sessionAttributeStore = sessionAttributeStore; - this.parameterNameDiscoverer = parameterNameDiscoverer; - this.customArgumentResolvers = customArgumentResolvers; - this.messageConverters = messageConverters; - } - - - public final Object invokeHandlerMethod(Method handlerMethod, Object handler, - NativeWebRequest webRequest, ExtendedModelMap implicitModel) throws Exception { - - Method handlerMethodToInvoke = BridgeMethodResolver.findBridgedMethod(handlerMethod); - try { - boolean debug = logger.isDebugEnabled(); - for (String attrName : this.methodResolver.getActualSessionAttributeNames()) { - Object attrValue = this.sessionAttributeStore.retrieveAttribute(webRequest, attrName); - if (attrValue != null) { - implicitModel.addAttribute(attrName, attrValue); - } - } - for (Method attributeMethod : this.methodResolver.getModelAttributeMethods()) { - Method attributeMethodToInvoke = BridgeMethodResolver.findBridgedMethod(attributeMethod); - Object[] args = resolveHandlerArguments(attributeMethodToInvoke, handler, webRequest, implicitModel); - if (debug) { - logger.debug("Invoking model attribute method: " + attributeMethodToInvoke); - } - String attrName = AnnotationUtils.findAnnotation(attributeMethod, ModelAttribute.class).value(); - if (!"".equals(attrName) && implicitModel.containsAttribute(attrName)) { - continue; - } - ReflectionUtils.makeAccessible(attributeMethodToInvoke); - Object attrValue = attributeMethodToInvoke.invoke(handler, args); - if ("".equals(attrName)) { - Class resolvedType = GenericTypeResolver.resolveReturnType(attributeMethodToInvoke, handler.getClass()); - attrName = Conventions.getVariableNameForReturnType(attributeMethodToInvoke, resolvedType, attrValue); - } - if (!implicitModel.containsAttribute(attrName)) { - implicitModel.addAttribute(attrName, attrValue); - } - } - Object[] args = resolveHandlerArguments(handlerMethodToInvoke, handler, webRequest, implicitModel); - if (debug) { - logger.debug("Invoking request handler method: " + handlerMethodToInvoke); - } - ReflectionUtils.makeAccessible(handlerMethodToInvoke); - return handlerMethodToInvoke.invoke(handler, args); - } catch (IllegalStateException ex) { - // Internal assertion failed (e.g. invalid signature): - // throw exception with full handler method context... - throw new HandlerMethodInvocationException(handlerMethodToInvoke, ex); - } catch (InvocationTargetException ex) { - // User-defined @ModelAttribute/@InitBinder/@RequestMapping method threw an exception... - ReflectionUtils.rethrowException(ex.getTargetException()); - return null; - } - } - - public final void updateModelAttributes(Object handler, Map mavModel, - ExtendedModelMap implicitModel, NativeWebRequest webRequest) throws Exception { - - if (this.methodResolver.hasSessionAttributes() && this.sessionStatus.isComplete()) { - for (String attrName : this.methodResolver.getActualSessionAttributeNames()) { - this.sessionAttributeStore.cleanupAttribute(webRequest, attrName); - } - } - - // Expose model attributes as session attributes, if required. - // Expose BindingResults for all attributes, making custom editors available. - Map model = (mavModel != null ? mavModel : implicitModel); - if (model != null) { - try { - String[] originalAttrNames = model.keySet().toArray(new String[model.size()]); - for (String attrName : originalAttrNames) { - Object attrValue = model.get(attrName); - boolean isSessionAttr = this.methodResolver.isSessionAttribute( - attrName, (attrValue != null ? attrValue.getClass() : null)); - if (isSessionAttr) { - if (this.sessionStatus.isComplete()) { - implicitModel.put(MODEL_KEY_PREFIX_STALE + attrName, Boolean.TRUE); - } else if (!implicitModel.containsKey(MODEL_KEY_PREFIX_STALE + attrName)) { - this.sessionAttributeStore.storeAttribute(webRequest, attrName, attrValue); - } - } - if (!attrName.startsWith(BindingResult.MODEL_KEY_PREFIX) && - (isSessionAttr || isBindingCandidate(attrValue))) { - String bindingResultKey = BindingResult.MODEL_KEY_PREFIX + attrName; - if (mavModel != null && !model.containsKey(bindingResultKey)) { - WebDataBinder binder = createBinder(webRequest, attrValue, attrName); - initBinder(handler, attrName, binder, webRequest); - mavModel.put(bindingResultKey, binder.getBindingResult()); - } - } - } - } catch (InvocationTargetException ex) { - // User-defined @InitBinder method threw an exception... - ReflectionUtils.rethrowException(ex.getTargetException()); - } - } - } - - - private Object[] resolveHandlerArguments(Method handlerMethod, Object handler, - NativeWebRequest webRequest, ExtendedModelMap implicitModel) throws Exception { - - Class[] paramTypes = handlerMethod.getParameterTypes(); - Object[] args = new Object[paramTypes.length]; - - for (int i = 0; i < args.length; i++) { - MethodParameter methodParam = new MethodParameter(handlerMethod, i); - methodParam.initParameterNameDiscovery(this.parameterNameDiscoverer); - GenericTypeResolver.resolveParameterType(methodParam, handler.getClass()); - String paramName = null; - String headerName = null; - boolean requestBodyFound = false; - String cookieName = null; - String pathVarName = null; - String attrName = null; - boolean required = false; - String defaultValue = null; - boolean validate = false; - int annotationsFound = 0; - Annotation[] paramAnns = methodParam.getParameterAnnotations(); - - for (Annotation paramAnn : paramAnns) { - if (RequestParam.class.isInstance(paramAnn)) { - RequestParam requestParam = (RequestParam) paramAnn; - paramName = requestParam.value(); - required = requestParam.required(); - defaultValue = parseDefaultValueAttribute(requestParam.defaultValue()); - annotationsFound++; - } else if (RequestHeader.class.isInstance(paramAnn)) { - RequestHeader requestHeader = (RequestHeader) paramAnn; - headerName = requestHeader.value(); - required = requestHeader.required(); - defaultValue = parseDefaultValueAttribute(requestHeader.defaultValue()); - annotationsFound++; - } else if (RequestBody.class.isInstance(paramAnn)) { - requestBodyFound = true; - annotationsFound++; - } else if (CookieValue.class.isInstance(paramAnn)) { - CookieValue cookieValue = (CookieValue) paramAnn; - cookieName = cookieValue.value(); - required = cookieValue.required(); - defaultValue = parseDefaultValueAttribute(cookieValue.defaultValue()); - annotationsFound++; - } else if (PathVariable.class.isInstance(paramAnn)) { - PathVariable pathVar = (PathVariable) paramAnn; - pathVarName = pathVar.value(); - annotationsFound++; - } else if (ModelAttribute.class.isInstance(paramAnn)) { - ModelAttribute attr = (ModelAttribute) paramAnn; - attrName = attr.value(); - annotationsFound++; - } else if (Value.class.isInstance(paramAnn)) { - defaultValue = ((Value) paramAnn).value(); - } else if ("Valid".equals(paramAnn.annotationType().getSimpleName())) { - validate = true; - } - } - - if (annotationsFound > 1) { - throw new IllegalStateException("Handler parameter annotations are exclusive choices - " + - "do not specify more than one such annotation on the same parameter: " + handlerMethod); - } - - if (annotationsFound == 0) { - Object argValue = resolveCommonArgument(methodParam, webRequest); - if (argValue != WebArgumentResolver.UNRESOLVED) { - args[i] = argValue; - } else if (defaultValue != null) { - args[i] = resolveDefaultValue(defaultValue); - } else { - Class paramType = methodParam.getParameterType(); - if (Model.class.isAssignableFrom(paramType) || Map.class.isAssignableFrom(paramType)) { - args[i] = implicitModel; - } else if (SessionStatus.class.isAssignableFrom(paramType)) { - args[i] = this.sessionStatus; - } else if (HttpEntity.class.isAssignableFrom(paramType)) { - args[i] = resolveHttpEntityRequest(methodParam, webRequest); - } else if (Errors.class.isAssignableFrom(paramType)) { - throw new IllegalStateException("Errors/BindingResult argument declared " + - "without preceding model attribute. Check your handler method signature!"); - } else if (BeanUtils.isSimpleProperty(paramType)) { - paramName = ""; - } else { - attrName = ""; - } - } - } - - if (paramName != null) { - args[i] = resolveRequestParam(paramName, required, defaultValue, methodParam, webRequest, handler); - } else if (headerName != null) { - args[i] = resolveRequestHeader(headerName, required, defaultValue, methodParam, webRequest, handler); - } else if (requestBodyFound) { - args[i] = resolveRequestBody(methodParam, webRequest, handler); - } else if (cookieName != null) { - args[i] = resolveCookieValue(cookieName, required, defaultValue, methodParam, webRequest, handler); - } else if (pathVarName != null) { - args[i] = resolvePathVariable(pathVarName, methodParam, webRequest, handler); - } else if (attrName != null) { - WebDataBinder binder = - resolveModelAttribute(attrName, methodParam, implicitModel, webRequest, handler); - boolean assignBindingResult = (args.length > i + 1 && Errors.class.isAssignableFrom(paramTypes[i + 1])); - if (binder.getTarget() != null) { - doBind(binder, webRequest, validate, !assignBindingResult); - } - args[i] = binder.getTarget(); - if (assignBindingResult) { - args[i + 1] = binder.getBindingResult(); - i++; - } - implicitModel.putAll(binder.getBindingResult().getModel()); - } - } - - return args; - } - - protected void initBinder(Object handler, String attrName, WebDataBinder binder, NativeWebRequest webRequest) - throws Exception { - - if (this.bindingInitializer != null) { - this.bindingInitializer.initBinder(binder, webRequest); - } - if (handler != null) { - Set initBinderMethods = this.methodResolver.getInitBinderMethods(); - if (!initBinderMethods.isEmpty()) { - boolean debug = logger.isDebugEnabled(); - for (Method initBinderMethod : initBinderMethods) { - Method methodToInvoke = BridgeMethodResolver.findBridgedMethod(initBinderMethod); - String[] targetNames = AnnotationUtils.findAnnotation(initBinderMethod, InitBinder.class).value(); - if (targetNames.length == 0 || Arrays.asList(targetNames).contains(attrName)) { - Object[] initBinderArgs = - resolveInitBinderArguments(handler, methodToInvoke, binder, webRequest); - if (debug) { - logger.debug("Invoking init-binder method: " + methodToInvoke); - } - ReflectionUtils.makeAccessible(methodToInvoke); - Object returnValue = methodToInvoke.invoke(handler, initBinderArgs); - if (returnValue != null) { - throw new IllegalStateException( - "InitBinder methods must not have a return value: " + methodToInvoke); - } - } - } - } - } - } - - private Object[] resolveInitBinderArguments(Object handler, Method initBinderMethod, - WebDataBinder binder, NativeWebRequest webRequest) throws Exception { - - Class[] initBinderParams = initBinderMethod.getParameterTypes(); - Object[] initBinderArgs = new Object[initBinderParams.length]; - - for (int i = 0; i < initBinderArgs.length; i++) { - MethodParameter methodParam = new MethodParameter(initBinderMethod, i); - methodParam.initParameterNameDiscovery(this.parameterNameDiscoverer); - GenericTypeResolver.resolveParameterType(methodParam, handler.getClass()); - String paramName = null; - boolean paramRequired = false; - String paramDefaultValue = null; - String pathVarName = null; - Annotation[] paramAnns = methodParam.getParameterAnnotations(); - - for (Annotation paramAnn : paramAnns) { - if (RequestParam.class.isInstance(paramAnn)) { - RequestParam requestParam = (RequestParam) paramAnn; - paramName = requestParam.value(); - paramRequired = requestParam.required(); - paramDefaultValue = parseDefaultValueAttribute(requestParam.defaultValue()); - break; - } else if (ModelAttribute.class.isInstance(paramAnn)) { - throw new IllegalStateException( - "@ModelAttribute is not supported on @InitBinder methods: " + initBinderMethod); - } else if (PathVariable.class.isInstance(paramAnn)) { - PathVariable pathVar = (PathVariable) paramAnn; - pathVarName = pathVar.value(); - } - } - - if (paramName == null && pathVarName == null) { - Object argValue = resolveCommonArgument(methodParam, webRequest); - if (argValue != WebArgumentResolver.UNRESOLVED) { - initBinderArgs[i] = argValue; - } else { - Class paramType = initBinderParams[i]; - if (paramType.isInstance(binder)) { - initBinderArgs[i] = binder; - } else if (BeanUtils.isSimpleProperty(paramType)) { - paramName = ""; - } else { - throw new IllegalStateException("Unsupported argument [" + paramType.getName() + - "] for @InitBinder method: " + initBinderMethod); - } - } - } - - if (paramName != null) { - initBinderArgs[i] = - resolveRequestParam(paramName, paramRequired, paramDefaultValue, methodParam, webRequest, null); - } else if (pathVarName != null) { - initBinderArgs[i] = resolvePathVariable(pathVarName, methodParam, webRequest, null); - } - } - - return initBinderArgs; - } - - @SuppressWarnings("unchecked") - private Object resolveRequestParam(String paramName, boolean required, String defaultValue, - MethodParameter methodParam, NativeWebRequest webRequest, Object handlerForInitBinderCall) - throws Exception { - - Class paramType = methodParam.getParameterType(); - if (Map.class.isAssignableFrom(paramType) && paramName.length() == 0) { - return resolveRequestParamMap((Class) paramType, webRequest); - } - if (paramName.length() == 0) { - paramName = getRequiredParameterName(methodParam); - } - Object paramValue = null; - MultipartRequest multipartRequest = webRequest.getNativeRequest(MultipartRequest.class); - if (multipartRequest != null) { - List files = multipartRequest.getFiles(paramName); - if (!files.isEmpty()) { - if (files.size() == 1 && !paramType.isArray() && !Collection.class.isAssignableFrom(paramType)) { - paramValue = files.get(0); - } else { - paramValue = files; - } - } - } - if (paramValue == null) { - String[] paramValues = webRequest.getParameterValues(paramName); - if (paramValues != null) { - if (paramValues.length == 1 && !paramType.isArray() && !Collection.class.isAssignableFrom(paramType)) { - paramValue = paramValues[0]; - } else { - paramValue = paramValues; - } - } - } - if (paramValue == null) { - if (defaultValue != null) { - paramValue = resolveDefaultValue(defaultValue); - } else if (required) { - raiseMissingParameterException(paramName, paramType); - } - paramValue = checkValue(paramName, paramValue, paramType); - } - WebDataBinder binder = createBinder(webRequest, null, paramName); - initBinder(handlerForInitBinderCall, paramName, binder, webRequest); - return binder.convertIfNecessary(paramValue, paramType, methodParam); - } - - private Map resolveRequestParamMap(Class mapType, NativeWebRequest webRequest) { - Map parameterMap = webRequest.getParameterMap(); - if (MultiValueMap.class.isAssignableFrom(mapType)) { - MultiValueMap result = new LinkedMultiValueMap(parameterMap.size()); - for (Map.Entry entry : parameterMap.entrySet()) { - for (String value : entry.getValue()) { - result.add(entry.getKey(), value); - } - } - return result; - } else { - Map result = new LinkedHashMap(parameterMap.size()); - for (Map.Entry entry : parameterMap.entrySet()) { - if (entry.getValue().length > 0) { - result.put(entry.getKey(), entry.getValue()[0]); - } - } - return result; - } - } - - @SuppressWarnings("unchecked") - private Object resolveRequestHeader(String headerName, boolean required, String defaultValue, - MethodParameter methodParam, NativeWebRequest webRequest, Object handlerForInitBinderCall) - throws Exception { - - Class paramType = methodParam.getParameterType(); - if (Map.class.isAssignableFrom(paramType)) { - return resolveRequestHeaderMap((Class) paramType, webRequest); - } - if (headerName.length() == 0) { - headerName = getRequiredParameterName(methodParam); - } - Object headerValue = null; - String[] headerValues = webRequest.getHeaderValues(headerName); - if (headerValues != null) { - headerValue = (headerValues.length == 1 ? headerValues[0] : headerValues); - } - if (headerValue == null) { - if (defaultValue != null) { - headerValue = resolveDefaultValue(defaultValue); - } else if (required) { - raiseMissingHeaderException(headerName, paramType); - } - headerValue = checkValue(headerName, headerValue, paramType); - } - WebDataBinder binder = createBinder(webRequest, null, headerName); - initBinder(handlerForInitBinderCall, headerName, binder, webRequest); - return binder.convertIfNecessary(headerValue, paramType, methodParam); - } - - private Map resolveRequestHeaderMap(Class mapType, NativeWebRequest webRequest) { - if (MultiValueMap.class.isAssignableFrom(mapType)) { - MultiValueMap result; - if (HttpHeaders.class.isAssignableFrom(mapType)) { - result = new HttpHeaders(); - } else { - result = new LinkedMultiValueMap(); - } - for (Iterator iterator = webRequest.getHeaderNames(); iterator.hasNext();) { - String headerName = iterator.next(); - for (String headerValue : webRequest.getHeaderValues(headerName)) { - result.add(headerName, headerValue); - } - } - return result; - } else { - Map result = new LinkedHashMap(); - for (Iterator iterator = webRequest.getHeaderNames(); iterator.hasNext();) { - String headerName = iterator.next(); - String headerValue = webRequest.getHeader(headerName); - result.put(headerName, headerValue); - } - return result; - } - } - - /** - * Resolves the given {@link RequestBody @RequestBody} annotation. - */ - protected Object resolveRequestBody(MethodParameter methodParam, NativeWebRequest webRequest, Object handler) - throws Exception { - - return readWithMessageConverters(methodParam, createHttpInputMessage(webRequest), methodParam.getParameterType()); - } - - private HttpEntity resolveHttpEntityRequest(MethodParameter methodParam, NativeWebRequest webRequest) - throws Exception { - - HttpInputMessage inputMessage = createHttpInputMessage(webRequest); - Class paramType = getHttpEntityType(methodParam); - Object body = readWithMessageConverters(methodParam, inputMessage, paramType); - return new HttpEntity(body, inputMessage.getHeaders()); - } - - private Object readWithMessageConverters(MethodParameter methodParam, HttpInputMessage inputMessage, Class paramType) - throws Exception { - - MediaType contentType = inputMessage.getHeaders().getContentType(); - if (contentType == null) { - StringBuilder builder = new StringBuilder(ClassUtils.getShortName(methodParam.getParameterType())); - String paramName = methodParam.getParameterName(); - if (paramName != null) { - builder.append(' '); - builder.append(paramName); - } - throw new HttpMediaTypeNotSupportedException( - "Cannot extract parameter (" + builder.toString() + "): no Content-Type found"); - } - - List allSupportedMediaTypes = new ArrayList(); - if (this.messageConverters != null) { - for (HttpMessageConverter messageConverter : this.messageConverters) { - allSupportedMediaTypes.addAll(messageConverter.getSupportedMediaTypes()); - if (messageConverter.canRead(paramType, contentType)) { - if (logger.isDebugEnabled()) { - logger.debug("Reading [" + paramType.getName() + "] as \"" + contentType - + "\" using [" + messageConverter + "]"); - } - return messageConverter.read(paramType, inputMessage); - } - } - } - throw new HttpMediaTypeNotSupportedException(contentType, allSupportedMediaTypes); - } - - private Class getHttpEntityType(MethodParameter methodParam) { - Assert.isAssignable(HttpEntity.class, methodParam.getParameterType()); - ParameterizedType type = (ParameterizedType) methodParam.getGenericParameterType(); - if (type.getActualTypeArguments().length == 1) { - Type typeArgument = type.getActualTypeArguments()[0]; - if (typeArgument instanceof Class) { - return (Class) typeArgument; - } else if (typeArgument instanceof GenericArrayType) { - Type componentType = ((GenericArrayType) typeArgument).getGenericComponentType(); - if (componentType instanceof Class) { - // Surely, there should be a nicer way to do this - Object array = Array.newInstance((Class) componentType, 0); - return array.getClass(); - } - } - } - throw new IllegalArgumentException( - "HttpEntity parameter (" + methodParam.getParameterName() + ") is not parameterized"); - - } - - private Object resolveCookieValue(String cookieName, boolean required, String defaultValue, - MethodParameter methodParam, NativeWebRequest webRequest, Object handlerForInitBinderCall) - throws Exception { - - Class paramType = methodParam.getParameterType(); - if (cookieName.length() == 0) { - cookieName = getRequiredParameterName(methodParam); - } - Object cookieValue = resolveCookieValue(cookieName, paramType, webRequest); - if (cookieValue == null) { - if (defaultValue != null) { - cookieValue = resolveDefaultValue(defaultValue); - } else if (required) { - raiseMissingCookieException(cookieName, paramType); - } - cookieValue = checkValue(cookieName, cookieValue, paramType); - } - WebDataBinder binder = createBinder(webRequest, null, cookieName); - initBinder(handlerForInitBinderCall, cookieName, binder, webRequest); - return binder.convertIfNecessary(cookieValue, paramType, methodParam); - } - - /** - * Resolves the given {@link CookieValue @CookieValue} annotation. - *

Throws an UnsupportedOperationException by default. - */ - protected Object resolveCookieValue(String cookieName, Class paramType, NativeWebRequest webRequest) - throws Exception { - - throw new UnsupportedOperationException("@CookieValue not supported"); - } - - private Object resolvePathVariable(String pathVarName, MethodParameter methodParam, - NativeWebRequest webRequest, Object handlerForInitBinderCall) throws Exception { - - Class paramType = methodParam.getParameterType(); - if (pathVarName.length() == 0) { - pathVarName = getRequiredParameterName(methodParam); - } - String pathVarValue = resolvePathVariable(pathVarName, paramType, webRequest); - WebDataBinder binder = createBinder(webRequest, null, pathVarName); - initBinder(handlerForInitBinderCall, pathVarName, binder, webRequest); - return binder.convertIfNecessary(pathVarValue, paramType, methodParam); - } - - /** - * Resolves the given {@link PathVariable @PathVariable} annotation. - *

Throws an UnsupportedOperationException by default. - */ - protected String resolvePathVariable(String pathVarName, Class paramType, NativeWebRequest webRequest) - throws Exception { - - throw new UnsupportedOperationException("@PathVariable not supported"); - } - - private String getRequiredParameterName(MethodParameter methodParam) { - String name = methodParam.getParameterName(); - if (name == null) { - throw new IllegalStateException( - "No parameter name specified for argument of type [" + methodParam.getParameterType().getName() + - "], and no parameter name information found in class file either."); - } - return name; - } - - private Object checkValue(String name, Object value, Class paramType) { - if (value == null) { - if (boolean.class.equals(paramType)) { - return Boolean.FALSE; - } else if (paramType.isPrimitive()) { - throw new IllegalStateException("Optional " + paramType + " parameter '" + name + - "' is not present but cannot be translated into a null value due to being declared as a " + - "primitive type. Consider declaring it as object wrapper for the corresponding primitive type."); - } - } - return value; - } - - private WebDataBinder resolveModelAttribute(String attrName, MethodParameter methodParam, - ExtendedModelMap implicitModel, NativeWebRequest webRequest, Object handler) throws Exception { - - // Bind request parameter onto object... - String name = attrName; - if ("".equals(name)) { - name = Conventions.getVariableNameForParameter(methodParam); - } - Class paramType = methodParam.getParameterType(); - Object bindObject; - if (implicitModel.containsKey(name)) { - bindObject = implicitModel.get(name); - } else if (this.methodResolver.isSessionAttribute(name, paramType)) { - bindObject = this.sessionAttributeStore.retrieveAttribute(webRequest, name); - if (bindObject == null) { - raiseSessionRequiredException("Session attribute '" + name + "' required - not found in session"); - } - } else { - bindObject = BeanUtils.instantiateClass(paramType); - } - WebDataBinder binder = createBinder(webRequest, bindObject, name); - initBinder(handler, name, binder, webRequest); - return binder; - } - - - /** - * Determine whether the given value qualifies as a "binding candidate", i.e. might potentially be subject to - * bean-style data binding later on. - */ - protected boolean isBindingCandidate(Object value) { - return (value != null && !value.getClass().isArray() && !(value instanceof Collection) && - !(value instanceof Map) && !BeanUtils.isSimpleValueType(value.getClass())); - } - - protected void raiseMissingParameterException(String paramName, Class paramType) throws Exception { - throw new IllegalStateException("Missing parameter '" + paramName + "' of type [" + paramType.getName() + "]"); - } - - protected void raiseMissingHeaderException(String headerName, Class paramType) throws Exception { - throw new IllegalStateException("Missing header '" + headerName + "' of type [" + paramType.getName() + "]"); - } - - protected void raiseMissingCookieException(String cookieName, Class paramType) throws Exception { - throw new IllegalStateException( - "Missing cookie value '" + cookieName + "' of type [" + paramType.getName() + "]"); - } - - protected void raiseSessionRequiredException(String message) throws Exception { - throw new IllegalStateException(message); - } - - protected WebDataBinder createBinder(NativeWebRequest webRequest, Object target, String objectName) - throws Exception { - - return new WebRequestDataBinder(target, objectName); - } - - private void doBind(WebDataBinder binder, NativeWebRequest webRequest, boolean validate, boolean failOnErrors) - throws Exception { - - doBind(binder, webRequest); - if (validate) { - binder.validate(); - } - if (failOnErrors && binder.getBindingResult().hasErrors()) { - throw new BindException(binder.getBindingResult()); - } - } - - protected void doBind(WebDataBinder binder, NativeWebRequest webRequest) throws Exception { - ((WebRequestDataBinder) binder).bind(webRequest); - } - - /** - * Return a {@link HttpInputMessage} for the given {@link NativeWebRequest}. - *

Throws an UnsupportedOperation1Exception by default. - */ - protected HttpInputMessage createHttpInputMessage(NativeWebRequest webRequest) throws Exception { - throw new UnsupportedOperationException("@RequestBody not supported"); - } - - /** - * Return a {@link HttpOutputMessage} for the given {@link NativeWebRequest}. - *

Throws an UnsupportedOperationException by default. - */ - protected HttpOutputMessage createHttpOutputMessage(NativeWebRequest webRequest) throws Exception { - throw new UnsupportedOperationException("@ResponseBody not supported"); - } - - protected String parseDefaultValueAttribute(String value) { - return (ValueConstants.DEFAULT_NONE.equals(value) ? null : value); - } - - protected Object resolveDefaultValue(String value) { - return value; - } - - protected Object resolveCommonArgument(MethodParameter methodParameter, NativeWebRequest webRequest) - throws Exception { - - // Invoke custom argument resolvers if present... - if (this.customArgumentResolvers != null) { - for (WebArgumentResolver argumentResolver : this.customArgumentResolvers) { - Object value = argumentResolver.resolveArgument(methodParameter, webRequest); - if (value != WebArgumentResolver.UNRESOLVED) { - return value; - } - } - } - - // Resolution of standard parameter types... - Class paramType = methodParameter.getParameterType(); - Object value = resolveStandardArgument(paramType, webRequest); - if (value != WebArgumentResolver.UNRESOLVED && !ClassUtils.isAssignableValue(paramType, value)) { - throw new IllegalStateException("Standard argument type [" + paramType.getName() + - "] resolved to incompatible value of type [" + (value != null ? value.getClass() : null) + - "]. Consider declaring the argument type in a less specific fashion."); - } - return value; - } - - protected Object resolveStandardArgument(Class parameterType, NativeWebRequest webRequest) throws Exception { - if (WebRequest.class.isAssignableFrom(parameterType)) { - return webRequest; - } - return WebArgumentResolver.UNRESOLVED; - } - - protected final void addReturnValueAsModelAttribute(Method handlerMethod, Class handlerType, - Object returnValue, ExtendedModelMap implicitModel) { - - ModelAttribute attr = AnnotationUtils.findAnnotation(handlerMethod, ModelAttribute.class); - String attrName = (attr != null ? attr.value() : ""); - if ("".equals(attrName)) { - Class resolvedType = GenericTypeResolver.resolveReturnType(handlerMethod, handlerType); - attrName = Conventions.getVariableNameForReturnType(handlerMethod, resolvedType, returnValue); - } - implicitModel.addAttribute(attrName, returnValue); - } - -} diff --git a/spring-data-document-core/src/main/java/org/springframework/data/document/web/servlet/ActionExecutedContext.java b/spring-data-document-core/src/main/java/org/springframework/data/document/web/servlet/ActionExecutedContext.java deleted file mode 100644 index 97123fdbe..000000000 --- a/spring-data-document-core/src/main/java/org/springframework/data/document/web/servlet/ActionExecutedContext.java +++ /dev/null @@ -1,58 +0,0 @@ -/* - * Copyright 2002-2010 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.springframework.data.document.web.servlet; - -import java.util.Arrays; - -import org.springframework.web.servlet.ModelAndView; - -public class ActionExecutedContext extends ActionExecutingContext { - - - private ModelAndView modelAndView; - - private Exception exception; - - public ActionExecutedContext(ActionExecutingContext actionExecutingContext, ModelAndView modelAndView, Exception exception) { - super(actionExecutingContext.getServletWebRequest(), actionExecutingContext.getHandler(), - actionExecutingContext.getHandlerMethod(), actionExecutingContext.getHandlerParameters(), - actionExecutingContext.getImplicitModel()); - this.modelAndView = modelAndView; - this.exception = exception; - } - - @Override - public String toString() { - return "ActionExecutedContext [handler=" + getHandler() - + ", servletWebRequest=" + getServletWebRequest() - + ", implicitModel=" + getImplicitModel() + ", handlerMethod=" - + getHandlerMethod() + ", handlerParameters=" - + Arrays.toString(getHandlerParameters()) + ",modelAndView=" + modelAndView - + ", exception=" + exception + "]"; - } - - - public ModelAndView getModelAndView() { - return modelAndView; - } - - - public Exception getException() { - return exception; - } - - -} diff --git a/spring-data-document-core/src/main/java/org/springframework/data/document/web/servlet/ActionExecutingContext.java b/spring-data-document-core/src/main/java/org/springframework/data/document/web/servlet/ActionExecutingContext.java deleted file mode 100644 index f87c63884..000000000 --- a/spring-data-document-core/src/main/java/org/springframework/data/document/web/servlet/ActionExecutingContext.java +++ /dev/null @@ -1,89 +0,0 @@ -/* - * Copyright 2002-2010 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.springframework.data.document.web.servlet; - -import java.lang.reflect.Method; -import java.util.Arrays; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; - -import org.springframework.ui.ExtendedModelMap; -import org.springframework.web.context.request.ServletWebRequest; - -public class ActionExecutingContext { - - - private Object handler; - - private ServletWebRequest servletWebRequest; - - private ExtendedModelMap implicitModel; - - private Method handlerMethod; - - private Object[] handlerParameters; - - - public ActionExecutingContext(ServletWebRequest servletWebRequest, - Object handler, Method handlerMethod, Object[] handlerParameters, - ExtendedModelMap implicitModel) { - super(); - this.servletWebRequest = servletWebRequest; - this.handler = handler; - this.handlerMethod = handlerMethod; - this.handlerParameters = handlerParameters; - this.implicitModel = implicitModel; - } - - public HttpServletRequest getHttpServletRequest() { - return servletWebRequest.getRequest(); - } - - public HttpServletResponse getHttpServletResponse() { - return servletWebRequest.getResponse(); - } - - public Object getHandler() { - return handler; - } - - public ServletWebRequest getServletWebRequest() { - return servletWebRequest; - } - - public ExtendedModelMap getImplicitModel() { - return implicitModel; - } - - public Method getHandlerMethod() { - return handlerMethod; - } - - public Object[] getHandlerParameters() { - return handlerParameters; - } - - @Override - public String toString() { - return "ActionExecutingContext [handler=" + handler - + ", servletWebRequest=" + servletWebRequest - + ", implicitModel=" + implicitModel + ", handlerMethod=" - + handlerMethod + ", handlerParameters=" - + Arrays.toString(handlerParameters) + "]"; - } - - -} diff --git a/spring-data-document-core/src/main/java/org/springframework/data/document/web/servlet/ActionInterceptor.java b/spring-data-document-core/src/main/java/org/springframework/data/document/web/servlet/ActionInterceptor.java deleted file mode 100644 index 6327c2605..000000000 --- a/spring-data-document-core/src/main/java/org/springframework/data/document/web/servlet/ActionInterceptor.java +++ /dev/null @@ -1,25 +0,0 @@ -/* - * Copyright 2002-2010 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.springframework.data.document.web.servlet; - -public interface ActionInterceptor { - - boolean preHandle(ActionExecutingContext actionExecutingContext); - - void postHandle(ActionExecutedContext actionExecutedContext); - - void afterCompletion(ActionExecutedContext actionExecutedContext); -} diff --git a/spring-data-document-core/src/main/java/org/springframework/data/document/web/servlet/mvc/annotation/AnnotationMethodHandlerAdapter.java b/spring-data-document-core/src/main/java/org/springframework/data/document/web/servlet/mvc/annotation/AnnotationMethodHandlerAdapter.java deleted file mode 100644 index 8761e5101..000000000 --- a/spring-data-document-core/src/main/java/org/springframework/data/document/web/servlet/mvc/annotation/AnnotationMethodHandlerAdapter.java +++ /dev/null @@ -1,1245 +0,0 @@ -/* - * Copyright 2002-2010 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.data.document.web.servlet.mvc.annotation; - -import java.io.*; -import java.lang.reflect.InvocationTargetException; -import java.lang.reflect.Method; -import java.security.Principal; -import java.util.*; -import java.util.concurrent.ConcurrentHashMap; -import javax.servlet.ServletException; -import javax.servlet.ServletRequest; -import javax.servlet.ServletResponse; -import javax.servlet.http.Cookie; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; -import javax.servlet.http.HttpSession; - -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; -import org.springframework.beans.BeanUtils; -import org.springframework.beans.factory.BeanFactory; -import org.springframework.beans.factory.BeanFactoryAware; -import org.springframework.beans.factory.config.BeanExpressionContext; -import org.springframework.beans.factory.config.BeanExpressionResolver; -import org.springframework.beans.factory.config.ConfigurableBeanFactory; -import org.springframework.core.*; -import org.springframework.core.annotation.AnnotationUtils; -import org.springframework.data.document.web.servlet.ActionExecutedContext; -import org.springframework.data.document.web.servlet.ActionExecutingContext; -import org.springframework.data.document.web.servlet.ActionInterceptor; -import org.springframework.data.document.web.servlet.mvc.annotation.support.InterceptingHandlerMethodInvoker; -import org.springframework.http.*; -import org.springframework.http.converter.ByteArrayHttpMessageConverter; -import org.springframework.http.converter.HttpMessageConverter; -import org.springframework.http.converter.StringHttpMessageConverter; -import org.springframework.http.converter.xml.SourceHttpMessageConverter; -import org.springframework.http.converter.xml.XmlAwareFormHttpMessageConverter; -import org.springframework.http.server.ServerHttpRequest; -import org.springframework.http.server.ServerHttpResponse; -import org.springframework.http.server.ServletServerHttpRequest; -import org.springframework.http.server.ServletServerHttpResponse; -import org.springframework.ui.ExtendedModelMap; -import org.springframework.ui.Model; -import org.springframework.util.*; -import org.springframework.validation.support.BindingAwareModelMap; -import org.springframework.web.HttpMediaTypeNotAcceptableException; -import org.springframework.web.HttpRequestMethodNotSupportedException; -import org.springframework.web.HttpSessionRequiredException; -import org.springframework.web.bind.MissingServletRequestParameterException; -import org.springframework.web.bind.ServletRequestDataBinder; -import org.springframework.web.bind.WebDataBinder; -import org.springframework.web.bind.annotation.*; -import org.springframework.web.bind.annotation.support.HandlerMethodInvocationException; -import org.springframework.web.bind.annotation.support.HandlerMethodInvoker; -import org.springframework.web.bind.annotation.support.HandlerMethodResolver; -import org.springframework.web.bind.support.DefaultSessionAttributeStore; -import org.springframework.web.bind.support.SessionAttributeStore; -import org.springframework.web.bind.support.WebArgumentResolver; -import org.springframework.web.bind.support.WebBindingInitializer; -import org.springframework.web.context.request.NativeWebRequest; -import org.springframework.web.context.request.RequestScope; -import org.springframework.web.context.request.ServletWebRequest; -import org.springframework.web.multipart.MultipartRequest; -import org.springframework.web.servlet.HandlerAdapter; -import org.springframework.web.servlet.HandlerMapping; -import org.springframework.web.servlet.ModelAndView; -import org.springframework.web.servlet.View; -import org.springframework.web.servlet.mvc.annotation.ModelAndViewResolver; -import org.springframework.web.servlet.mvc.multiaction.InternalPathMethodNameResolver; -import org.springframework.web.servlet.mvc.multiaction.MethodNameResolver; -import org.springframework.web.servlet.mvc.multiaction.NoSuchRequestHandlingMethodException; -import org.springframework.web.servlet.support.RequestContextUtils; -import org.springframework.web.servlet.support.WebContentGenerator; -import org.springframework.web.util.UrlPathHelper; -import org.springframework.web.util.WebUtils; - -/** - * Implementation of the {@link org.springframework.web.servlet.HandlerAdapter} interface - * that maps handler methods based on HTTP paths, HTTP methods and request parameters - * expressed through the {@link RequestMapping} annotation. - *

- *

Supports request parameter binding through the {@link RequestParam} annotation. - * Also supports the {@link ModelAttribute} annotation for exposing model attribute - * values to the view, as well as {@link InitBinder} for binder initialization methods - * and {@link SessionAttributes} for automatic session management of specific attributes. - *

- *

This adapter can be customized through various bean properties. - * A common use case is to apply shared binder initialization logic through - * a custom {@link #setWebBindingInitializer WebBindingInitializer}. - * - * @author Juergen Hoeller - * @author Arjen Poutsma - * @see #setPathMatcher - * @see #setMethodNameResolver - * @see #setWebBindingInitializer - * @see #setSessionAttributeStore - * @since 2.5 - */ -public class AnnotationMethodHandlerAdapter extends WebContentGenerator - implements HandlerAdapter, Ordered, BeanFactoryAware { - - - private ActionInterceptor[] actionInterceptors; - - /** - * Log category to use when no mapped handler is found for a request. - * - * @see #pageNotFoundLogger - */ - public static final String PAGE_NOT_FOUND_LOG_CATEGORY = "org.springframework.web.servlet.PageNotFound"; - - /** - * Additional logger to use when no mapped handler is found for a request. - * - * @see #PAGE_NOT_FOUND_LOG_CATEGORY - */ - protected static final Log pageNotFoundLogger = LogFactory.getLog(PAGE_NOT_FOUND_LOG_CATEGORY); - - - private UrlPathHelper urlPathHelper = new UrlPathHelper(); - - private PathMatcher pathMatcher = new AntPathMatcher(); - - private MethodNameResolver methodNameResolver = new InternalPathMethodNameResolver(); - - private WebBindingInitializer webBindingInitializer; - - private SessionAttributeStore amhaSessionAttributeStore = new DefaultSessionAttributeStore(); - - private int cacheSecondsForSessionAttributeHandlers = 0; - - private boolean synchronizeOnSession = false; - - private ParameterNameDiscoverer parameterNameDiscoverer = new LocalVariableTableParameterNameDiscoverer(); - - private WebArgumentResolver[] customArgumentResolvers; - - private ModelAndViewResolver[] customModelAndViewResolvers; - - private HttpMessageConverter[] messageConverters; - - private int order = Ordered.LOWEST_PRECEDENCE; - - private ConfigurableBeanFactory beanFactory; - - private BeanExpressionContext expressionContext; - - private final Map, ServletHandlerMethodResolver> methodResolverCache = - new ConcurrentHashMap, ServletHandlerMethodResolver>(); - - - public AnnotationMethodHandlerAdapter() { - // no restriction of HTTP methods by default - // MLP - super(false); - - // See SPR-7316 - StringHttpMessageConverter stringHttpMessageConverter = new StringHttpMessageConverter(); - stringHttpMessageConverter.setWriteAcceptCharset(false); - messageConverters = new HttpMessageConverter[]{new ByteArrayHttpMessageConverter(), stringHttpMessageConverter, - new SourceHttpMessageConverter(), new XmlAwareFormHttpMessageConverter()}; - } - - - /** - * Set if URL lookup should always use the full path within the current servlet - * context. Else, the path within the current servlet mapping is used if applicable - * (that is, in the case of a ".../*" servlet mapping in web.xml). - *

Default is "false". - * - * @see org.springframework.web.util.UrlPathHelper#setAlwaysUseFullPath - */ - public void setAlwaysUseFullPath(boolean alwaysUseFullPath) { - this.urlPathHelper.setAlwaysUseFullPath(alwaysUseFullPath); - } - - /** - * Set if context path and request URI should be URL-decoded. Both are returned - * undecoded by the Servlet API, in contrast to the servlet path. - *

Uses either the request encoding or the default encoding according - * to the Servlet spec (ISO-8859-1). - * - * @see org.springframework.web.util.UrlPathHelper#setUrlDecode - */ - public void setUrlDecode(boolean urlDecode) { - this.urlPathHelper.setUrlDecode(urlDecode); - } - - /** - * Set the UrlPathHelper to use for resolution of lookup paths. - *

Use this to override the default UrlPathHelper with a custom subclass, - * or to share common UrlPathHelper settings across multiple HandlerMappings and HandlerAdapters. - */ - public void setUrlPathHelper(UrlPathHelper urlPathHelper) { - Assert.notNull(urlPathHelper, "UrlPathHelper must not be null"); - this.urlPathHelper = urlPathHelper; - } - - /** - * Set the PathMatcher implementation to use for matching URL paths against registered URL patterns. - *

Default is {@link org.springframework.util.AntPathMatcher}. - */ - public void setPathMatcher(PathMatcher pathMatcher) { - Assert.notNull(pathMatcher, "PathMatcher must not be null"); - this.pathMatcher = pathMatcher; - } - - /** - * Set the MethodNameResolver to use for resolving default handler methods - * (carrying an empty @RequestMapping annotation). - *

Will only kick in when the handler method cannot be resolved uniquely - * through the annotation metadata already. - */ - public void setMethodNameResolver(MethodNameResolver methodNameResolver) { - this.methodNameResolver = methodNameResolver; - } - - /** - * Specify a WebBindingInitializer which will apply pre-configured - * configuration to every DataBinder that this controller uses. - */ - public void setWebBindingInitializer(WebBindingInitializer webBindingInitializer) { - this.webBindingInitializer = webBindingInitializer; - } - - /** - * Specify the strategy to store session attributes with. - *

Default is {@link org.springframework.web.bind.support.DefaultSessionAttributeStore}, - * storing session attributes in the HttpSession, using the same attribute name as in the model. - */ - public void setSessionAttributeStore(SessionAttributeStore sessionAttributeStore) { - Assert.notNull(sessionAttributeStore, "SessionAttributeStore must not be null"); - this.amhaSessionAttributeStore = sessionAttributeStore; - } - - /** - * Cache content produced by @SessionAttributes annotated handlers - * for the given number of seconds. Default is 0, preventing caching completely. - *

In contrast to the "cacheSeconds" property which will apply to all general handlers - * (but not to @SessionAttributes annotated handlers), this setting will - * apply to @SessionAttributes annotated handlers only. - * - * @see #setCacheSeconds - * @see org.springframework.web.bind.annotation.SessionAttributes - */ - public void setCacheSecondsForSessionAttributeHandlers(int cacheSecondsForSessionAttributeHandlers) { - this.cacheSecondsForSessionAttributeHandlers = cacheSecondsForSessionAttributeHandlers; - } - - /** - * Set if controller execution should be synchronized on the session, - * to serialize parallel invocations from the same client. - *

More specifically, the execution of the handleRequestInternal - * method will get synchronized if this flag is "true". The best available - * session mutex will be used for the synchronization; ideally, this will - * be a mutex exposed by HttpSessionMutexListener. - *

The session mutex is guaranteed to be the same object during - * the entire lifetime of the session, available under the key defined - * by the SESSION_MUTEX_ATTRIBUTE constant. It serves as a - * safe reference to synchronize on for locking on the current session. - *

In many cases, the HttpSession reference itself is a safe mutex - * as well, since it will always be the same object reference for the - * same active logical session. However, this is not guaranteed across - * different servlet containers; the only 100% safe way is a session mutex. - * - * @see org.springframework.web.util.HttpSessionMutexListener - * @see org.springframework.web.util.WebUtils#getSessionMutex(javax.servlet.http.HttpSession) - */ - public void setSynchronizeOnSession(boolean synchronizeOnSession) { - this.synchronizeOnSession = synchronizeOnSession; - } - - /** - * Set the ParameterNameDiscoverer to use for resolving method parameter names if needed - * (e.g. for default attribute names). - *

Default is a {@link org.springframework.core.LocalVariableTableParameterNameDiscoverer}. - */ - public void setParameterNameDiscoverer(ParameterNameDiscoverer parameterNameDiscoverer) { - this.parameterNameDiscoverer = parameterNameDiscoverer; - } - - /** - * Set a custom WebArgumentResolvers to use for special method parameter types. - *

Such a custom WebArgumentResolver will kick in first, having a chance to resolve - * an argument value before the standard argument handling kicks in. - */ - public void setCustomArgumentResolver(WebArgumentResolver argumentResolver) { - this.customArgumentResolvers = new WebArgumentResolver[]{argumentResolver}; - } - - /** - * Set one or more custom WebArgumentResolvers to use for special method parameter types. - *

Any such custom WebArgumentResolver will kick in first, having a chance to resolve - * an argument value before the standard argument handling kicks in. - */ - public void setCustomArgumentResolvers(WebArgumentResolver[] argumentResolvers) { - this.customArgumentResolvers = argumentResolvers; - } - - /** - * Set a custom ModelAndViewResolvers to use for special method return types. - *

Such a custom ModelAndViewResolver will kick in first, having a chance to resolve - * a return value before the standard ModelAndView handling kicks in. - */ - public void setCustomModelAndViewResolver(ModelAndViewResolver customModelAndViewResolver) { - this.customModelAndViewResolvers = new ModelAndViewResolver[]{customModelAndViewResolver}; - } - - /** - * Set one or more custom ModelAndViewResolvers to use for special method return types. - *

Any such custom ModelAndViewResolver will kick in first, having a chance to resolve - * a return value before the standard ModelAndView handling kicks in. - */ - public void setCustomModelAndViewResolvers(ModelAndViewResolver[] customModelAndViewResolvers) { - this.customModelAndViewResolvers = customModelAndViewResolvers; - } - - /** - * Set the message body converters to use. - *

These converters are used to convert from and to HTTP requests and responses. - */ - public void setMessageConverters(HttpMessageConverter[] messageConverters) { - this.messageConverters = messageConverters; - } - - /** - * Return the message body converters that this adapter has been configured with. - */ - public HttpMessageConverter[] getMessageConverters() { - return messageConverters; - } - - public void setActionInterceptors(ActionInterceptor[] actionInterceptors) { - this.actionInterceptors = actionInterceptors; - } - - /** - * Specify the order value for this HandlerAdapter bean. - *

Default value is Integer.MAX_VALUE, meaning that it's non-ordered. - * - * @see org.springframework.core.Ordered#getOrder() - */ - public void setOrder(int order) { - this.order = order; - } - - public int getOrder() { - return this.order; - } - - public void setBeanFactory(BeanFactory beanFactory) { - if (beanFactory instanceof ConfigurableBeanFactory) { - this.beanFactory = (ConfigurableBeanFactory) beanFactory; - this.expressionContext = new BeanExpressionContext(this.beanFactory, new RequestScope()); - } - } - - - public boolean supports(Object handler) { - return getMethodResolver(handler).hasHandlerMethods(); - } - - public ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler) - throws Exception { - - if (AnnotationUtils.findAnnotation(handler.getClass(), SessionAttributes.class) != null) { - // Always prevent caching in case of session attribute management. - checkAndPrepare(request, response, this.cacheSecondsForSessionAttributeHandlers, true); - // Prepare cached set of session attributes names. - } else { - // Uses configured default cacheSeconds setting. - checkAndPrepare(request, response, true); - } - - // Execute invokeHandlerMethod in synchronized block if required. - if (this.synchronizeOnSession) { - HttpSession session = request.getSession(false); - if (session != null) { - Object mutex = WebUtils.getSessionMutex(session); - synchronized (mutex) { - return invokeHandlerMethod(request, response, handler); - } - } - } - - return invokeHandlerMethod(request, response, handler); - } - - protected ModelAndView invokeHandlerMethod(HttpServletRequest request, HttpServletResponse response, Object handler) - throws Exception { - - ServletHandlerMethodResolver methodResolver = getMethodResolver(handler); - Method handlerMethod = methodResolver.resolveHandlerMethod(request); - ServletHandlerMethodInvoker methodInvoker = new ServletHandlerMethodInvoker(methodResolver, actionInterceptors); - ServletWebRequest webRequest = new ServletWebRequest(request, response); - ExtendedModelMap implicitModel = new BindingAwareModelMap(); - - - return methodInvoker.interceptingInvokeHandlerMethod(handlerMethod, handler, webRequest, implicitModel); - //Object result = methodInvoker.invokeHandlerMethod(handlerMethod, handler, webRequest, implicitModel); - //ModelAndView mav = - // methodInvoker.getModelAndView(handlerMethod, handler.getClass(), result, implicitModel, webRequest); - // methodInvoker.updateModelAttributes(handler, (mav != null ? mav.getModel() : null), implicitModel, webRequest); - // return mav; - } - - public long getLastModified(HttpServletRequest request, Object handler) { - return -1; - } - - /** - * Build a HandlerMethodResolver for the given handler type. - */ - private ServletHandlerMethodResolver getMethodResolver(Object handler) { - Class handlerClass = ClassUtils.getUserClass(handler); - ServletHandlerMethodResolver resolver = this.methodResolverCache.get(handlerClass); - if (resolver == null) { - resolver = new ServletHandlerMethodResolver(handlerClass); - this.methodResolverCache.put(handlerClass, resolver); - } - return resolver; - } - - - /** - * Template method for creating a new ServletRequestDataBinder instance. - *

The default implementation creates a standard ServletRequestDataBinder. - * This can be overridden for custom ServletRequestDataBinder subclasses. - * - * @param request current HTTP request - * @param target the target object to bind onto (or null - * if the binder is just used to convert a plain parameter value) - * @param objectName the objectName of the target object - * @return the ServletRequestDataBinder instance to use - * @throws Exception in case of invalid state or arguments - * @see ServletRequestDataBinder#bind(javax.servlet.ServletRequest) - * @see ServletRequestDataBinder#convertIfNecessary(Object, Class, org.springframework.core.MethodParameter) - */ - protected ServletRequestDataBinder createBinder(HttpServletRequest request, Object target, String objectName) - throws Exception { - return new ServletRequestDataBinder(target, objectName); - } - - /** - * Template method for creating a new HttpInputMessage instance. - *

The default implementation creates a standard {@link ServletServerHttpRequest}. - * This can be overridden for custom {@code HttpInputMessage} implementations - * - * @param servletRequest current HTTP request - * @return the HttpInputMessage instance to use - * @throws Exception in case of errors - */ - protected HttpInputMessage createHttpInputMessage(HttpServletRequest servletRequest) throws Exception { - return new ServletServerHttpRequest(servletRequest); - } - - /** - * Template method for creating a new HttpOuputMessage instance. - *

The default implementation creates a standard {@link ServletServerHttpResponse}. - * This can be overridden for custom {@code HttpOutputMessage} implementations - * - * @param servletResponse current HTTP response - * @return the HttpInputMessage instance to use - * @throws Exception in case of errors - */ - protected HttpOutputMessage createHttpOutputMessage(HttpServletResponse servletResponse) throws Exception { - return new ServletServerHttpResponse(servletResponse); - } - - - /** - * Servlet-specific subclass of {@link HandlerMethodResolver}. - */ - private class ServletHandlerMethodResolver extends HandlerMethodResolver { - - private final Map mappings = new HashMap(); - - private ServletHandlerMethodResolver(Class handlerType) { - init(handlerType); - } - - @Override - protected boolean isHandlerMethod(Method method) { - if (this.mappings.containsKey(method)) { - return true; - } - RequestMapping mapping = AnnotationUtils.findAnnotation(method, RequestMapping.class); - if (mapping != null) { - RequestMappingInfo mappingInfo = new RequestMappingInfo(); - mappingInfo.patterns = mapping.value(); - if (!hasTypeLevelMapping() || !Arrays.equals(mapping.method(), getTypeLevelMapping().method())) { - mappingInfo.methods = mapping.method(); - } - if (!hasTypeLevelMapping() || !Arrays.equals(mapping.params(), getTypeLevelMapping().params())) { - mappingInfo.params = mapping.params(); - } - if (!hasTypeLevelMapping() || !Arrays.equals(mapping.headers(), getTypeLevelMapping().headers())) { - mappingInfo.headers = mapping.headers(); - } - this.mappings.put(method, mappingInfo); - return true; - } - return false; - } - - public Method resolveHandlerMethod(HttpServletRequest request) throws ServletException { - String lookupPath = urlPathHelper.getLookupPathForRequest(request); - Comparator pathComparator = pathMatcher.getPatternComparator(lookupPath); - Map targetHandlerMethods = new LinkedHashMap(); - Set allowedMethods = new LinkedHashSet(7); - String resolvedMethodName = null; - for (Method handlerMethod : getHandlerMethods()) { - RequestMappingInfo mappingInfo = this.mappings.get(handlerMethod); - boolean match = false; - if (mappingInfo.hasPatterns()) { - List matchingPatterns = new ArrayList(mappingInfo.patterns.length); - for (String pattern : mappingInfo.patterns) { - if (!hasTypeLevelMapping() && !pattern.startsWith("/")) { - pattern = "/" + pattern; - } - String combinedPattern = getCombinedPattern(pattern, lookupPath, request); - if (combinedPattern != null) { - if (mappingInfo.matches(request)) { - match = true; - matchingPatterns.add(combinedPattern); - } else { - if (!mappingInfo.matchesRequestMethod(request)) { - allowedMethods.addAll(mappingInfo.methodNames()); - } - break; - } - } - } - Collections.sort(matchingPatterns, pathComparator); - mappingInfo.matchedPatterns = matchingPatterns; - } else { - // No paths specified: parameter match sufficient. - match = mappingInfo.matches(request); - if (match && mappingInfo.methods.length == 0 && mappingInfo.params.length == 0 && - resolvedMethodName != null && !resolvedMethodName.equals(handlerMethod.getName())) { - match = false; - } else { - if (!mappingInfo.matchesRequestMethod(request)) { - allowedMethods.addAll(mappingInfo.methodNames()); - } - } - } - if (match) { - Method oldMappedMethod = targetHandlerMethods.put(mappingInfo, handlerMethod); - if (oldMappedMethod != null && oldMappedMethod != handlerMethod) { - if (methodNameResolver != null && mappingInfo.patterns.length == 0) { - if (!oldMappedMethod.getName().equals(handlerMethod.getName())) { - if (resolvedMethodName == null) { - resolvedMethodName = methodNameResolver.getHandlerMethodName(request); - } - if (!resolvedMethodName.equals(oldMappedMethod.getName())) { - oldMappedMethod = null; - } - if (!resolvedMethodName.equals(handlerMethod.getName())) { - if (oldMappedMethod != null) { - targetHandlerMethods.put(mappingInfo, oldMappedMethod); - oldMappedMethod = null; - } else { - targetHandlerMethods.remove(mappingInfo); - } - } - } - } - if (oldMappedMethod != null) { - throw new IllegalStateException( - "Ambiguous handler methods mapped for HTTP path '" + lookupPath + "': {" + - oldMappedMethod + ", " + handlerMethod + - "}. If you intend to handle the same path in multiple methods, then factor " + - "them out into a dedicated handler class with that path mapped at the type level!"); - } - } - } - } - if (!targetHandlerMethods.isEmpty()) { - List matches = new ArrayList(targetHandlerMethods.keySet()); - RequestMappingInfoComparator requestMappingInfoComparator = - new RequestMappingInfoComparator(pathComparator, request); - Collections.sort(matches, requestMappingInfoComparator); - RequestMappingInfo bestMappingMatch = matches.get(0); - String bestMatchedPath = bestMappingMatch.bestMatchedPattern(); - if (bestMatchedPath != null) { - extractHandlerMethodUriTemplates(bestMatchedPath, lookupPath, request); - } - return targetHandlerMethods.get(bestMappingMatch); - } else { - if (!allowedMethods.isEmpty()) { - throw new HttpRequestMethodNotSupportedException(request.getMethod(), - StringUtils.toStringArray(allowedMethods)); - } - throw new NoSuchRequestHandlingMethodException(lookupPath, request.getMethod(), - request.getParameterMap()); - } - } - - /** - * Determines the combined pattern for the given methodLevelPattern and path. - *

Uses the following algorithm:

    - *
  1. If there is a type-level mapping with path information, it is {@linkplain - * PathMatcher#combine(String, String) combined} with the method-level pattern.
  2. - *
  3. If there is a {@linkplain HandlerMapping#BEST_MATCHING_PATTERN_ATTRIBUTE best matching pattern} in the - * request, it is combined with the method-level pattern.
  4. - *
  5. Otherwise, the method-level pattern is returned.
  6. - *
- */ - private String getCombinedPattern(String methodLevelPattern, String lookupPath, HttpServletRequest request) { - if (hasTypeLevelMapping() && (!ObjectUtils.isEmpty(getTypeLevelMapping().value()))) { - String[] typeLevelPatterns = getTypeLevelMapping().value(); - for (String typeLevelPattern : typeLevelPatterns) { - if (!typeLevelPattern.startsWith("/")) { - typeLevelPattern = "/" + typeLevelPattern; - } - String combinedPattern = pathMatcher.combine(typeLevelPattern, methodLevelPattern); - if (isPathMatchInternal(combinedPattern, lookupPath)) { - return combinedPattern; - } - } - return null; - } - String bestMatchingPattern = (String) request.getAttribute(HandlerMapping.BEST_MATCHING_PATTERN_ATTRIBUTE); - if (StringUtils.hasText(bestMatchingPattern) && bestMatchingPattern.endsWith("*")) { - String combinedPattern = pathMatcher.combine(bestMatchingPattern, methodLevelPattern); - if (!combinedPattern.equals(bestMatchingPattern) && - (isPathMatchInternal(combinedPattern, lookupPath))) { - return combinedPattern; - } - } - if (isPathMatchInternal(methodLevelPattern, lookupPath)) { - return methodLevelPattern; - } - return null; - } - - private boolean isPathMatchInternal(String pattern, String lookupPath) { - if (pattern.equals(lookupPath) || pathMatcher.match(pattern, lookupPath)) { - return true; - } - boolean hasSuffix = pattern.indexOf('.') != -1; - if (!hasSuffix && pathMatcher.match(pattern + ".*", lookupPath)) { - return true; - } - boolean endsWithSlash = pattern.endsWith("/"); - if (!endsWithSlash && pathMatcher.match(pattern + "/", lookupPath)) { - return true; - } - return false; - } - - @SuppressWarnings("unchecked") - private void extractHandlerMethodUriTemplates(String mappedPattern, - String lookupPath, - HttpServletRequest request) { - - Map variables = - (Map) request.getAttribute(HandlerMapping.URI_TEMPLATE_VARIABLES_ATTRIBUTE); - - int patternVariableCount = StringUtils.countOccurrencesOf(mappedPattern, "{"); - - if ((variables == null || patternVariableCount != variables.size()) - && pathMatcher.match(mappedPattern, lookupPath)) { - variables = pathMatcher.extractUriTemplateVariables(mappedPattern, lookupPath); - request.setAttribute(HandlerMapping.URI_TEMPLATE_VARIABLES_ATTRIBUTE, variables); - } - } - } - - - /** - * Servlet-specific subclass of {@link HandlerMethodInvoker}. - */ - private class ServletHandlerMethodInvoker extends InterceptingHandlerMethodInvoker { - - private boolean responseArgumentUsed = false; - - private ServletHandlerMethodInvoker(HandlerMethodResolver resolver, ActionInterceptor[] actionInterceptors) { - super(resolver, webBindingInitializer, amhaSessionAttributeStore, parameterNameDiscoverer, - customArgumentResolvers, messageConverters, actionInterceptors); - } - - public ModelAndView interceptingInvokeHandlerMethod(Method handlerMethod, Object handler, - NativeWebRequest webRequest, ExtendedModelMap implicitModel) throws Exception { - - int interceptorIndex = -1; - ModelAndView mav = null; - ActionExecutingContext executingContext = null; - Method handlerMethodToInvoke = BridgeMethodResolver.findBridgedMethod(handlerMethod); - try { - boolean debug = logger.isDebugEnabled(); - for (String attrName : this.methodResolver.getActualSessionAttributeNames()) { - Object attrValue = this.sessionAttributeStore.retrieveAttribute(webRequest, attrName); - if (attrValue != null) { - implicitModel.addAttribute(attrName, attrValue); - } - } - for (Method attributeMethod : this.methodResolver.getModelAttributeMethods()) { - Method attributeMethodToInvoke = BridgeMethodResolver.findBridgedMethod(attributeMethod); - Object[] args = resolveHandlerArguments(attributeMethodToInvoke, handler, webRequest, implicitModel); - if (debug) { - logger.debug("Invoking model attribute method: " + attributeMethodToInvoke); - } - String attrName = AnnotationUtils.findAnnotation(attributeMethod, ModelAttribute.class).value(); - if (!"".equals(attrName) && implicitModel.containsAttribute(attrName)) { - continue; - } - ReflectionUtils.makeAccessible(attributeMethodToInvoke); - Object attrValue = attributeMethodToInvoke.invoke(handler, args); - if ("".equals(attrName)) { - Class resolvedType = GenericTypeResolver.resolveReturnType(attributeMethodToInvoke, handler.getClass()); - attrName = Conventions.getVariableNameForReturnType(attributeMethodToInvoke, resolvedType, attrValue); - } - if (!implicitModel.containsAttribute(attrName)) { - implicitModel.addAttribute(attrName, attrValue); - } - } - Object[] args = resolveHandlerArguments(handlerMethodToInvoke, handler, webRequest, implicitModel); - if (debug) { - logger.debug("Invoking request handler method: " + handlerMethodToInvoke); - } - ReflectionUtils.makeAccessible(handlerMethodToInvoke); - - executingContext = new ActionExecutingContext((ServletWebRequest) webRequest, handler, handlerMethodToInvoke, args, implicitModel); - - // Apply preHandle methods of registered interceptors. - ActionInterceptor[] interceptors = getActionInterceptors(); - if (interceptors != null) { - for (int i = 0; i < interceptors.length; i++) { - ActionInterceptor interceptor = interceptors[i]; - if (!interceptor.preHandle(executingContext)) { - triggerAfterCompletion(executingContext, interceptorIndex, null, null); - return null; //TODO verify null is ok - } - interceptorIndex = i; - } - } - - // Actually invoke the handler - Object result = handlerMethodToInvoke.invoke(handler, args); - - - mav = getModelAndView(handlerMethod, handler.getClass(), result, implicitModel, (ServletWebRequest) webRequest); - updateModelAttributes(handler, (mav != null ? mav.getModel() : null), implicitModel, webRequest); - - // Trigger after-completion for successful outcome - triggerAfterCompletion(executingContext, interceptorIndex, mav, null); - - return mav; - } catch (IllegalStateException ex) { - // Internal assertion failed (e.g. invalid signature): - // throw exception with full handler method context... - triggerAfterCompletion(executingContext, interceptorIndex, mav, ex); - throw new HandlerMethodInvocationException(handlerMethodToInvoke, ex); - } catch (InvocationTargetException ex) { - // User-defined @ModelAttribute/@InitBinder/@RequestMapping method threw an exception... - triggerAfterCompletion(executingContext, interceptorIndex, mav, ex); - ReflectionUtils.rethrowException(ex.getTargetException()); - return null; - } - } - - private void triggerAfterCompletion(ActionExecutingContext executingContext, - int interceptorIndex, - ModelAndView modelAndView, - Exception ex) throws Exception { - - // Apply afterCompletion methods of registered interceptors. - if (executingContext.getHandler() != null) { - //TODO should be passed in; - ActionInterceptor[] interceptors = getActionInterceptors(); - if (interceptors != null) { - for (int i = interceptorIndex; i >= 0; i--) { - ActionInterceptor interceptor = interceptors[i]; - ActionExecutedContext actionExecutedContext = new ActionExecutedContext(executingContext, modelAndView, ex); - try { - interceptor.afterCompletion(actionExecutedContext); - } catch (Throwable ex2) { - logger.error("ActionInterceptor threw exception", ex2); - } - } - } - } - } - - - @Override - protected void raiseMissingParameterException(String paramName, Class paramType) throws Exception { - throw new MissingServletRequestParameterException(paramName, paramType.getSimpleName()); - } - - @Override - protected void raiseSessionRequiredException(String message) throws Exception { - throw new HttpSessionRequiredException(message); - } - - @Override - protected WebDataBinder createBinder(NativeWebRequest webRequest, Object target, String objectName) - throws Exception { - - return AnnotationMethodHandlerAdapter.this.createBinder( - webRequest.getNativeRequest(HttpServletRequest.class), target, objectName); - } - - @Override - protected void doBind(WebDataBinder binder, NativeWebRequest webRequest) throws Exception { - ServletRequestDataBinder servletBinder = (ServletRequestDataBinder) binder; - servletBinder.bind(webRequest.getNativeRequest(ServletRequest.class)); - } - - @Override - protected HttpInputMessage createHttpInputMessage(NativeWebRequest webRequest) throws Exception { - HttpServletRequest servletRequest = webRequest.getNativeRequest(HttpServletRequest.class); - return AnnotationMethodHandlerAdapter.this.createHttpInputMessage(servletRequest); - } - - @Override - protected HttpOutputMessage createHttpOutputMessage(NativeWebRequest webRequest) throws Exception { - HttpServletResponse servletResponse = (HttpServletResponse) webRequest.getNativeResponse(); - return AnnotationMethodHandlerAdapter.this.createHttpOutputMessage(servletResponse); - } - - @Override - protected Object resolveDefaultValue(String value) { - if (beanFactory == null) { - return value; - } - String placeholdersResolved = beanFactory.resolveEmbeddedValue(value); - BeanExpressionResolver exprResolver = beanFactory.getBeanExpressionResolver(); - if (exprResolver == null) { - return value; - } - return exprResolver.evaluate(placeholdersResolved, expressionContext); - } - - @Override - protected Object resolveCookieValue(String cookieName, Class paramType, NativeWebRequest webRequest) - throws Exception { - - HttpServletRequest servletRequest = webRequest.getNativeRequest(HttpServletRequest.class); - Cookie cookieValue = WebUtils.getCookie(servletRequest, cookieName); - if (Cookie.class.isAssignableFrom(paramType)) { - return cookieValue; - } else if (cookieValue != null) { - return urlPathHelper.decodeRequestString(servletRequest, cookieValue.getValue()); - } else { - return null; - } - } - - @Override - @SuppressWarnings({"unchecked"}) - protected String resolvePathVariable(String pathVarName, Class paramType, NativeWebRequest webRequest) - throws Exception { - - HttpServletRequest servletRequest = webRequest.getNativeRequest(HttpServletRequest.class); - Map uriTemplateVariables = - (Map) servletRequest.getAttribute(HandlerMapping.URI_TEMPLATE_VARIABLES_ATTRIBUTE); - if (uriTemplateVariables == null || !uriTemplateVariables.containsKey(pathVarName)) { - throw new IllegalStateException( - "Could not find @PathVariable [" + pathVarName + "] in @RequestMapping"); - } - return uriTemplateVariables.get(pathVarName); - } - - @Override - protected Object resolveStandardArgument(Class parameterType, NativeWebRequest webRequest) throws Exception { - HttpServletRequest request = webRequest.getNativeRequest(HttpServletRequest.class); - HttpServletResponse response = webRequest.getNativeResponse(HttpServletResponse.class); - - if (ServletRequest.class.isAssignableFrom(parameterType) || - MultipartRequest.class.isAssignableFrom(parameterType)) { - Object nativeRequest = webRequest.getNativeRequest(parameterType); - if (nativeRequest == null) { - throw new IllegalStateException( - "Current request is not of type [" + parameterType.getName() + "]: " + request); - } - return nativeRequest; - } else if (ServletResponse.class.isAssignableFrom(parameterType)) { - this.responseArgumentUsed = true; - Object nativeResponse = webRequest.getNativeResponse(parameterType); - if (nativeResponse == null) { - throw new IllegalStateException( - "Current response is not of type [" + parameterType.getName() + "]: " + response); - } - return nativeResponse; - } else if (HttpSession.class.isAssignableFrom(parameterType)) { - return request.getSession(); - } else if (Principal.class.isAssignableFrom(parameterType)) { - return request.getUserPrincipal(); - } else if (Locale.class.equals(parameterType)) { - return RequestContextUtils.getLocale(request); - } else if (InputStream.class.isAssignableFrom(parameterType)) { - return request.getInputStream(); - } else if (Reader.class.isAssignableFrom(parameterType)) { - return request.getReader(); - } else if (OutputStream.class.isAssignableFrom(parameterType)) { - this.responseArgumentUsed = true; - return response.getOutputStream(); - } else if (Writer.class.isAssignableFrom(parameterType)) { - this.responseArgumentUsed = true; - return response.getWriter(); - } - return super.resolveStandardArgument(parameterType, webRequest); - } - - @SuppressWarnings("unchecked") - public ModelAndView getModelAndView(Method handlerMethod, Class handlerType, Object returnValue, - ExtendedModelMap implicitModel, ServletWebRequest webRequest) throws Exception { - - ResponseStatus responseStatusAnn = AnnotationUtils.findAnnotation(handlerMethod, ResponseStatus.class); - if (responseStatusAnn != null) { - HttpStatus responseStatus = responseStatusAnn.value(); - String reason = responseStatusAnn.reason(); - if (!StringUtils.hasText(reason)) { - webRequest.getResponse().setStatus(responseStatus.value()); - } else { - webRequest.getResponse().sendError(responseStatus.value(), reason); - } - - // to be picked up by the RedirectView - webRequest.getRequest().setAttribute(View.RESPONSE_STATUS_ATTRIBUTE, responseStatus); - - responseArgumentUsed = true; - } - - // Invoke custom resolvers if present... - if (customModelAndViewResolvers != null) { - for (ModelAndViewResolver mavResolver : customModelAndViewResolvers) { - ModelAndView mav = mavResolver.resolveModelAndView( - handlerMethod, handlerType, returnValue, implicitModel, webRequest); - if (mav != ModelAndViewResolver.UNRESOLVED) { - return mav; - } - } - } - - if (returnValue instanceof HttpEntity) { - handleHttpEntityResponse((HttpEntity) returnValue, webRequest); - return null; - } else if (AnnotationUtils.findAnnotation(handlerMethod, ResponseBody.class) != null) { - handleResponseBody(returnValue, webRequest); - return null; - } else if (returnValue instanceof ModelAndView) { - ModelAndView mav = (ModelAndView) returnValue; - mav.getModelMap().mergeAttributes(implicitModel); - return mav; - } else if (returnValue instanceof Model) { - return new ModelAndView().addAllObjects(implicitModel).addAllObjects(((Model) returnValue).asMap()); - } else if (returnValue instanceof View) { - return new ModelAndView((View) returnValue).addAllObjects(implicitModel); - } else if (AnnotationUtils.findAnnotation(handlerMethod, ModelAttribute.class) != null) { - addReturnValueAsModelAttribute(handlerMethod, handlerType, returnValue, implicitModel); - return new ModelAndView().addAllObjects(implicitModel); - } else if (returnValue instanceof Map) { - return new ModelAndView().addAllObjects(implicitModel).addAllObjects((Map) returnValue); - } else if (returnValue instanceof String) { - return new ModelAndView((String) returnValue).addAllObjects(implicitModel); - } else if (returnValue == null) { - // Either returned null or was 'void' return. - if (this.responseArgumentUsed || webRequest.isNotModified()) { - return null; - } else { - // Assuming view name translation... - return new ModelAndView().addAllObjects(implicitModel); - } - } else if (!BeanUtils.isSimpleProperty(returnValue.getClass())) { - // Assume a single model attribute... - addReturnValueAsModelAttribute(handlerMethod, handlerType, returnValue, implicitModel); - return new ModelAndView().addAllObjects(implicitModel); - } else { - throw new IllegalArgumentException("Invalid handler method return value: " + returnValue); - } - } - - private void handleResponseBody(Object returnValue, ServletWebRequest webRequest) - throws Exception { - if (returnValue == null) { - return; - } - HttpInputMessage inputMessage = createHttpInputMessage(webRequest); - HttpOutputMessage outputMessage = createHttpOutputMessage(webRequest); - writeWithMessageConverters(returnValue, inputMessage, outputMessage); - } - - private void handleHttpEntityResponse(HttpEntity responseEntity, ServletWebRequest webRequest) - throws Exception { - if (responseEntity == null) { - return; - } - HttpInputMessage inputMessage = createHttpInputMessage(webRequest); - HttpOutputMessage outputMessage = createHttpOutputMessage(webRequest); - if (responseEntity instanceof ResponseEntity && outputMessage instanceof ServerHttpResponse) { - ((ServerHttpResponse) outputMessage).setStatusCode(((ResponseEntity) responseEntity).getStatusCode()); - } - HttpHeaders entityHeaders = responseEntity.getHeaders(); - if (!entityHeaders.isEmpty()) { - outputMessage.getHeaders().putAll(entityHeaders); - } - Object body = responseEntity.getBody(); - if (body != null) { - writeWithMessageConverters(body, inputMessage, outputMessage); - } else { - // flush headers - outputMessage.getBody(); - } - } - - @SuppressWarnings("unchecked") - private void writeWithMessageConverters(Object returnValue, - HttpInputMessage inputMessage, HttpOutputMessage outputMessage) - throws IOException, HttpMediaTypeNotAcceptableException { - List acceptedMediaTypes = inputMessage.getHeaders().getAccept(); - if (acceptedMediaTypes.isEmpty()) { - acceptedMediaTypes = Collections.singletonList(MediaType.ALL); - } - MediaType.sortByQualityValue(acceptedMediaTypes); - Class returnValueType = returnValue.getClass(); - List allSupportedMediaTypes = new ArrayList(); - if (getMessageConverters() != null) { - for (MediaType acceptedMediaType : acceptedMediaTypes) { - for (HttpMessageConverter messageConverter : getMessageConverters()) { - if (messageConverter.canWrite(returnValueType, acceptedMediaType)) { - messageConverter.write(returnValue, acceptedMediaType, outputMessage); - if (logger.isDebugEnabled()) { - MediaType contentType = outputMessage.getHeaders().getContentType(); - if (contentType == null) { - contentType = acceptedMediaType; - } - logger.debug("Written [" + returnValue + "] as \"" + contentType + - "\" using [" + messageConverter + "]"); - } - this.responseArgumentUsed = true; - return; - } - } - } - for (HttpMessageConverter messageConverter : messageConverters) { - allSupportedMediaTypes.addAll(messageConverter.getSupportedMediaTypes()); - } - } - throw new HttpMediaTypeNotAcceptableException(allSupportedMediaTypes); - } - - } - - - /** - * Holder for request mapping metadata. Allows for finding a best matching candidate. - */ - static class RequestMappingInfo { - - String[] patterns = new String[0]; - - List matchedPatterns = Collections.emptyList(); - - RequestMethod[] methods = new RequestMethod[0]; - - String[] params = new String[0]; - - String[] headers = new String[0]; - - public boolean hasPatterns() { - return patterns.length > 0; - } - - public String bestMatchedPattern() { - return (!this.matchedPatterns.isEmpty() ? this.matchedPatterns.get(0) : null); - } - - public boolean matches(HttpServletRequest request) { - return matchesRequestMethod(request) && matchesParameters(request) && matchesHeaders(request); - } - - public boolean matchesHeaders(HttpServletRequest request) { - return ServletAnnotationMappingUtils.checkHeaders(this.headers, request); - } - - public boolean matchesParameters(HttpServletRequest request) { - return ServletAnnotationMappingUtils.checkParameters(this.params, request); - } - - public boolean matchesRequestMethod(HttpServletRequest request) { - return ServletAnnotationMappingUtils.checkRequestMethod(this.methods, request); - } - - public Set methodNames() { - Set methodNames = new LinkedHashSet(methods.length); - for (RequestMethod method : methods) { - methodNames.add(method.name()); - } - return methodNames; - } - - @Override - public boolean equals(Object obj) { - RequestMappingInfo other = (RequestMappingInfo) obj; - return (Arrays.equals(this.patterns, other.patterns) && Arrays.equals(this.methods, other.methods) && - Arrays.equals(this.params, other.params) && Arrays.equals(this.headers, other.headers)); - } - - @Override - public int hashCode() { - return (Arrays.hashCode(this.patterns) * 23 + Arrays.hashCode(this.methods) * 29 + - Arrays.hashCode(this.params) * 31 + Arrays.hashCode(this.headers)); - } - - @Override - public String toString() { - StringBuilder builder = new StringBuilder(); - builder.append(Arrays.asList(patterns)); - if (methods.length > 0) { - builder.append(','); - builder.append(Arrays.asList(methods)); - } - if (headers.length > 0) { - builder.append(','); - builder.append(Arrays.asList(headers)); - } - if (params.length > 0) { - builder.append(','); - builder.append(Arrays.asList(params)); - } - return builder.toString(); - } - } - - - /** - * Comparator capable of sorting {@link RequestMappingInfo}s (RHIs) so that sorting a list with this comparator will - * result in: - *
    - *
  • RHIs with {@linkplain RequestMappingInfo#matchedPatterns better matched paths} take prescedence - * over those with a weaker match (as expressed by the {@linkplain PathMatcher#getPatternComparator(String) path - * pattern comparator}.) Typically, this means that patterns without wild cards and uri templates will be ordered - * before those without.
  • - *
  • RHIs with one single {@linkplain RequestMappingInfo#methods request method} will be - * ordered before those without a method, or with more than one method.
  • - *
  • RHIs with more {@linkplain RequestMappingInfo#params request parameters} will be ordered before those with - * less parameters
  • - * - */ - static class RequestMappingInfoComparator implements Comparator { - - private final Comparator pathComparator; - - private final ServerHttpRequest request; - - RequestMappingInfoComparator(Comparator pathComparator, HttpServletRequest request) { - this.pathComparator = pathComparator; - this.request = new ServletServerHttpRequest(request); - } - - public int compare(RequestMappingInfo info1, RequestMappingInfo info2) { - int pathComparison = pathComparator.compare(info1.bestMatchedPattern(), info2.bestMatchedPattern()); - if (pathComparison != 0) { - return pathComparison; - } - int info1ParamCount = info1.params.length; - int info2ParamCount = info2.params.length; - if (info1ParamCount != info2ParamCount) { - return info2ParamCount - info1ParamCount; - } - int info1HeaderCount = info1.headers.length; - int info2HeaderCount = info2.headers.length; - if (info1HeaderCount != info2HeaderCount) { - return info2HeaderCount - info1HeaderCount; - } - int acceptComparison = compareAcceptHeaders(info1, info2); - if (acceptComparison != 0) { - return acceptComparison; - } - int info1MethodCount = info1.methods.length; - int info2MethodCount = info2.methods.length; - if (info1MethodCount == 0 && info2MethodCount > 0) { - return 1; - } else if (info2MethodCount == 0 && info1MethodCount > 0) { - return -1; - } else if (info1MethodCount == 1 & info2MethodCount > 1) { - return -1; - } else if (info2MethodCount == 1 & info1MethodCount > 1) { - return 1; - } - return 0; - } - - private int compareAcceptHeaders(RequestMappingInfo info1, RequestMappingInfo info2) { - List requestAccepts = request.getHeaders().getAccept(); - MediaType.sortByQualityValue(requestAccepts); - - List info1Accepts = getAcceptHeaderValue(info1); - List info2Accepts = getAcceptHeaderValue(info2); - - for (MediaType requestAccept : requestAccepts) { - int pos1 = indexOfIncluded(info1Accepts, requestAccept); - int pos2 = indexOfIncluded(info2Accepts, requestAccept); - if (pos1 != pos2) { - return pos2 - pos1; - } - } - return 0; - } - - private int indexOfIncluded(List infoAccepts, MediaType requestAccept) { - for (int i = 0; i < infoAccepts.size(); i++) { - MediaType info1Accept = infoAccepts.get(i); - if (requestAccept.includes(info1Accept)) { - return i; - } - } - return -1; - } - - private List getAcceptHeaderValue(RequestMappingInfo info) { - for (String header : info.headers) { - int separator = header.indexOf('='); - if (separator != -1) { - String key = header.substring(0, separator); - String value = header.substring(separator + 1); - if ("Accept".equalsIgnoreCase(key)) { - return MediaType.parseMediaTypes(value); - } - } - } - return Collections.emptyList(); - } - } - -} diff --git a/spring-data-document-core/src/main/java/org/springframework/data/document/web/servlet/mvc/annotation/ServletAnnotationMappingUtils.java b/spring-data-document-core/src/main/java/org/springframework/data/document/web/servlet/mvc/annotation/ServletAnnotationMappingUtils.java deleted file mode 100644 index 5d0bd7386..000000000 --- a/spring-data-document-core/src/main/java/org/springframework/data/document/web/servlet/mvc/annotation/ServletAnnotationMappingUtils.java +++ /dev/null @@ -1,141 +0,0 @@ -/* - * Copyright 2002-2010 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.data.document.web.servlet.mvc.annotation; - -import java.util.Iterator; -import java.util.List; -import javax.servlet.http.HttpServletRequest; - -import org.springframework.http.MediaType; -import org.springframework.util.ObjectUtils; -import org.springframework.web.bind.annotation.RequestMethod; -import org.springframework.web.util.WebUtils; - -/** - * Helper class for annotation-based request mapping. - * - * @author Juergen Hoeller - * @author Arjen Poutsma - * @since 2.5.2 - */ -abstract class ServletAnnotationMappingUtils { - - /** - * Check whether the given request matches the specified request methods. - * - * @param methods the HTTP request methods to check against - * @param request the current HTTP request to check - */ - public static boolean checkRequestMethod(RequestMethod[] methods, HttpServletRequest request) { - if (ObjectUtils.isEmpty(methods)) { - return true; - } - for (RequestMethod method : methods) { - if (method.name().equals(request.getMethod())) { - return true; - } - } - return false; - } - - /** - * Check whether the given request matches the specified parameter conditions. - * - * @param params the parameter conditions, following - * {@link org.springframework.web.bind.annotation.RequestMapping#params() RequestMapping.#params()} - * @param request the current HTTP request to check - */ - public static boolean checkParameters(String[] params, HttpServletRequest request) { - if (!ObjectUtils.isEmpty(params)) { - for (String param : params) { - int separator = param.indexOf('='); - if (separator == -1) { - if (param.startsWith("!")) { - if (WebUtils.hasSubmitParameter(request, param.substring(1))) { - return false; - } - } else if (!WebUtils.hasSubmitParameter(request, param)) { - return false; - } - } else { - boolean negated = separator > 0 && param.charAt(separator - 1) == '!'; - String key = !negated ? param.substring(0, separator) : param.substring(0, separator - 1); - String value = param.substring(separator + 1); - if (!value.equals(request.getParameter(key))) { - return negated; - } - } - } - } - return true; - } - - /** - * Check whether the given request matches the specified header conditions. - * - * @param headers the header conditions, following - * {@link org.springframework.web.bind.annotation.RequestMapping#headers() RequestMapping.headers()} - * @param request the current HTTP request to check - */ - public static boolean checkHeaders(String[] headers, HttpServletRequest request) { - if (!ObjectUtils.isEmpty(headers)) { - for (String header : headers) { - int separator = header.indexOf('='); - if (separator == -1) { - if (header.startsWith("!")) { - if (request.getHeader(header.substring(1)) != null) { - return false; - } - } else if (request.getHeader(header) == null) { - return false; - } - } else { - boolean negated = separator > 0 && header.charAt(separator - 1) == '!'; - String key = !negated ? header.substring(0, separator) : header.substring(0, separator - 1); - String value = header.substring(separator + 1); - if (isMediaTypeHeader(key)) { - List requestMediaTypes = MediaType.parseMediaTypes(request.getHeader(key)); - List valueMediaTypes = MediaType.parseMediaTypes(value); - boolean found = false; - for (Iterator valIter = valueMediaTypes.iterator(); valIter.hasNext() && !found;) { - MediaType valueMediaType = valIter.next(); - for (Iterator reqIter = requestMediaTypes.iterator(); - reqIter.hasNext() && !found;) { - MediaType requestMediaType = reqIter.next(); - if (valueMediaType.includes(requestMediaType)) { - found = true; - } - } - - } - if (!found) { - return negated; - } - } else if (!value.equals(request.getHeader(key))) { - return negated; - } - } - } - } - return true; - } - - private static boolean isMediaTypeHeader(String headerName) { - return "Accept".equalsIgnoreCase(headerName) || "Content-Type".equalsIgnoreCase(headerName); - } - -} diff --git a/spring-data-document-core/src/main/java/org/springframework/data/document/web/servlet/mvc/annotation/support/InterceptingHandlerMethodInvoker.java b/spring-data-document-core/src/main/java/org/springframework/data/document/web/servlet/mvc/annotation/support/InterceptingHandlerMethodInvoker.java deleted file mode 100644 index 76abcbc31..000000000 --- a/spring-data-document-core/src/main/java/org/springframework/data/document/web/servlet/mvc/annotation/support/InterceptingHandlerMethodInvoker.java +++ /dev/null @@ -1,828 +0,0 @@ -/* - * Copyright 2002-2010 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.data.document.web.servlet.mvc.annotation.support; - -import java.lang.annotation.Annotation; -import java.lang.reflect.*; -import java.util.*; - -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; -import org.springframework.beans.BeanUtils; -import org.springframework.beans.factory.annotation.Value; -import org.springframework.core.*; -import org.springframework.core.annotation.AnnotationUtils; -import org.springframework.data.document.web.servlet.ActionInterceptor; -import org.springframework.http.*; -import org.springframework.http.converter.HttpMessageConverter; -import org.springframework.ui.ExtendedModelMap; -import org.springframework.ui.Model; -import org.springframework.util.*; -import org.springframework.validation.BindException; -import org.springframework.validation.BindingResult; -import org.springframework.validation.Errors; -import org.springframework.web.HttpMediaTypeNotSupportedException; -import org.springframework.web.bind.WebDataBinder; -import org.springframework.web.bind.annotation.*; -import org.springframework.web.bind.annotation.support.HandlerMethodInvocationException; -import org.springframework.web.bind.annotation.support.HandlerMethodResolver; -import org.springframework.web.bind.support.*; -import org.springframework.web.context.request.NativeWebRequest; -import org.springframework.web.context.request.WebRequest; -import org.springframework.web.multipart.MultipartFile; -import org.springframework.web.multipart.MultipartRequest; - -/** - * Support class for invoking an annotated handler method. Operates on the introspection results of a {@link - * HandlerMethodResolver} for a specific handler type. - *

    - *

    Used by {@link org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter} and {@link - * org.springframework.web.portlet.mvc.annotation.AnnotationMethodHandlerAdapter}. - * - * @author Juergen Hoeller - * @author Arjen Poutsma - * @see #invokeHandlerMethod - * @since 2.5.2 - */ -public class InterceptingHandlerMethodInvoker { - - private static final String MODEL_KEY_PREFIX_STALE = SessionAttributeStore.class.getName() + ".STALE."; - - /** - * We'll create a lot of these objects, so we don't want a new logger every time. - */ - private static final Log logger = LogFactory.getLog(InterceptingHandlerMethodInvoker.class); - - protected final HandlerMethodResolver methodResolver; - - private final WebBindingInitializer bindingInitializer; - - protected final SessionAttributeStore sessionAttributeStore; - - private final ParameterNameDiscoverer parameterNameDiscoverer; - - private final WebArgumentResolver[] customArgumentResolvers; - - private final HttpMessageConverter[] messageConverters; - - private final ActionInterceptor[] actionInterceptors; - - private final SimpleSessionStatus sessionStatus = new SimpleSessionStatus(); - - - public InterceptingHandlerMethodInvoker(HandlerMethodResolver methodResolver) { - this(methodResolver, null); - } - - public InterceptingHandlerMethodInvoker(HandlerMethodResolver methodResolver, WebBindingInitializer bindingInitializer) { - this(methodResolver, bindingInitializer, new DefaultSessionAttributeStore(), null, null, null, null); - } - - public InterceptingHandlerMethodInvoker(HandlerMethodResolver methodResolver, WebBindingInitializer bindingInitializer, - SessionAttributeStore sessionAttributeStore, ParameterNameDiscoverer parameterNameDiscoverer, - WebArgumentResolver[] customArgumentResolvers, HttpMessageConverter[] messageConverters, ActionInterceptor[] actionInterceptors) { - - this.methodResolver = methodResolver; - this.bindingInitializer = bindingInitializer; - this.sessionAttributeStore = sessionAttributeStore; - this.parameterNameDiscoverer = parameterNameDiscoverer; - this.customArgumentResolvers = customArgumentResolvers; - this.messageConverters = messageConverters; - this.actionInterceptors = actionInterceptors; - } - - protected ActionInterceptor[] getActionInterceptors() { - return actionInterceptors; - } - - - public final Object invokeHandlerMethod(Method handlerMethod, Object handler, - NativeWebRequest webRequest, ExtendedModelMap implicitModel) throws Exception { - - Method handlerMethodToInvoke = BridgeMethodResolver.findBridgedMethod(handlerMethod); - try { - boolean debug = logger.isDebugEnabled(); - for (String attrName : this.methodResolver.getActualSessionAttributeNames()) { - Object attrValue = this.sessionAttributeStore.retrieveAttribute(webRequest, attrName); - if (attrValue != null) { - implicitModel.addAttribute(attrName, attrValue); - } - } - for (Method attributeMethod : this.methodResolver.getModelAttributeMethods()) { - Method attributeMethodToInvoke = BridgeMethodResolver.findBridgedMethod(attributeMethod); - Object[] args = resolveHandlerArguments(attributeMethodToInvoke, handler, webRequest, implicitModel); - if (debug) { - logger.debug("Invoking model attribute method: " + attributeMethodToInvoke); - } - String attrName = AnnotationUtils.findAnnotation(attributeMethod, ModelAttribute.class).value(); - if (!"".equals(attrName) && implicitModel.containsAttribute(attrName)) { - continue; - } - ReflectionUtils.makeAccessible(attributeMethodToInvoke); - Object attrValue = attributeMethodToInvoke.invoke(handler, args); - if ("".equals(attrName)) { - Class resolvedType = GenericTypeResolver.resolveReturnType(attributeMethodToInvoke, handler.getClass()); - attrName = Conventions.getVariableNameForReturnType(attributeMethodToInvoke, resolvedType, attrValue); - } - if (!implicitModel.containsAttribute(attrName)) { - implicitModel.addAttribute(attrName, attrValue); - } - } - Object[] args = resolveHandlerArguments(handlerMethodToInvoke, handler, webRequest, implicitModel); - if (debug) { - logger.debug("Invoking request handler method: " + handlerMethodToInvoke); - } - ReflectionUtils.makeAccessible(handlerMethodToInvoke); - return handlerMethodToInvoke.invoke(handler, args); - } catch (IllegalStateException ex) { - // Internal assertion failed (e.g. invalid signature): - // throw exception with full handler method context... - throw new HandlerMethodInvocationException(handlerMethodToInvoke, ex); - } catch (InvocationTargetException ex) { - // User-defined @ModelAttribute/@InitBinder/@RequestMapping method threw an exception... - ReflectionUtils.rethrowException(ex.getTargetException()); - return null; - } - } - - public final void updateModelAttributes(Object handler, Map mavModel, - ExtendedModelMap implicitModel, NativeWebRequest webRequest) throws Exception { - - if (this.methodResolver.hasSessionAttributes() && this.sessionStatus.isComplete()) { - for (String attrName : this.methodResolver.getActualSessionAttributeNames()) { - this.sessionAttributeStore.cleanupAttribute(webRequest, attrName); - } - } - - // Expose model attributes as session attributes, if required. - // Expose BindingResults for all attributes, making custom editors available. - Map model = (mavModel != null ? mavModel : implicitModel); - if (model != null) { - try { - String[] originalAttrNames = model.keySet().toArray(new String[model.size()]); - for (String attrName : originalAttrNames) { - Object attrValue = model.get(attrName); - boolean isSessionAttr = this.methodResolver.isSessionAttribute( - attrName, (attrValue != null ? attrValue.getClass() : null)); - if (isSessionAttr) { - if (this.sessionStatus.isComplete()) { - implicitModel.put(MODEL_KEY_PREFIX_STALE + attrName, Boolean.TRUE); - } else if (!implicitModel.containsKey(MODEL_KEY_PREFIX_STALE + attrName)) { - this.sessionAttributeStore.storeAttribute(webRequest, attrName, attrValue); - } - } - if (!attrName.startsWith(BindingResult.MODEL_KEY_PREFIX) && - (isSessionAttr || isBindingCandidate(attrValue))) { - String bindingResultKey = BindingResult.MODEL_KEY_PREFIX + attrName; - if (mavModel != null && !model.containsKey(bindingResultKey)) { - WebDataBinder binder = createBinder(webRequest, attrValue, attrName); - initBinder(handler, attrName, binder, webRequest); - mavModel.put(bindingResultKey, binder.getBindingResult()); - } - } - } - } catch (InvocationTargetException ex) { - // User-defined @InitBinder method threw an exception... - ReflectionUtils.rethrowException(ex.getTargetException()); - } - } - } - - - protected Object[] resolveHandlerArguments(Method handlerMethod, Object handler, - NativeWebRequest webRequest, ExtendedModelMap implicitModel) throws Exception { - - Class[] paramTypes = handlerMethod.getParameterTypes(); - Object[] args = new Object[paramTypes.length]; - - for (int i = 0; i < args.length; i++) { - MethodParameter methodParam = new MethodParameter(handlerMethod, i); - methodParam.initParameterNameDiscovery(this.parameterNameDiscoverer); - GenericTypeResolver.resolveParameterType(methodParam, handler.getClass()); - String paramName = null; - String headerName = null; - boolean requestBodyFound = false; - String cookieName = null; - String pathVarName = null; - String attrName = null; - boolean required = false; - String defaultValue = null; - boolean validate = false; - int annotationsFound = 0; - Annotation[] paramAnns = methodParam.getParameterAnnotations(); - - for (Annotation paramAnn : paramAnns) { - if (RequestParam.class.isInstance(paramAnn)) { - RequestParam requestParam = (RequestParam) paramAnn; - paramName = requestParam.value(); - required = requestParam.required(); - defaultValue = parseDefaultValueAttribute(requestParam.defaultValue()); - annotationsFound++; - } else if (RequestHeader.class.isInstance(paramAnn)) { - RequestHeader requestHeader = (RequestHeader) paramAnn; - headerName = requestHeader.value(); - required = requestHeader.required(); - defaultValue = parseDefaultValueAttribute(requestHeader.defaultValue()); - annotationsFound++; - } else if (RequestBody.class.isInstance(paramAnn)) { - requestBodyFound = true; - annotationsFound++; - } else if (CookieValue.class.isInstance(paramAnn)) { - CookieValue cookieValue = (CookieValue) paramAnn; - cookieName = cookieValue.value(); - required = cookieValue.required(); - defaultValue = parseDefaultValueAttribute(cookieValue.defaultValue()); - annotationsFound++; - } else if (PathVariable.class.isInstance(paramAnn)) { - PathVariable pathVar = (PathVariable) paramAnn; - pathVarName = pathVar.value(); - annotationsFound++; - } else if (ModelAttribute.class.isInstance(paramAnn)) { - ModelAttribute attr = (ModelAttribute) paramAnn; - attrName = attr.value(); - annotationsFound++; - } else if (Value.class.isInstance(paramAnn)) { - defaultValue = ((Value) paramAnn).value(); - } else if ("Valid".equals(paramAnn.annotationType().getSimpleName())) { - validate = true; - } - } - - if (annotationsFound > 1) { - throw new IllegalStateException("Handler parameter annotations are exclusive choices - " + - "do not specify more than one such annotation on the same parameter: " + handlerMethod); - } - - if (annotationsFound == 0) { - Object argValue = resolveCommonArgument(methodParam, webRequest); - if (argValue != WebArgumentResolver.UNRESOLVED) { - args[i] = argValue; - } else if (defaultValue != null) { - args[i] = resolveDefaultValue(defaultValue); - } else { - Class paramType = methodParam.getParameterType(); - if (Model.class.isAssignableFrom(paramType) || Map.class.isAssignableFrom(paramType)) { - args[i] = implicitModel; - } else if (SessionStatus.class.isAssignableFrom(paramType)) { - args[i] = this.sessionStatus; - } else if (HttpEntity.class.isAssignableFrom(paramType)) { - args[i] = resolveHttpEntityRequest(methodParam, webRequest); - } else if (Errors.class.isAssignableFrom(paramType)) { - throw new IllegalStateException("Errors/BindingResult argument declared " + - "without preceding model attribute. Check your handler method signature!"); - } else if (BeanUtils.isSimpleProperty(paramType)) { - paramName = ""; - } else { - attrName = ""; - } - } - } - - if (paramName != null) { - args[i] = resolveRequestParam(paramName, required, defaultValue, methodParam, webRequest, handler); - } else if (headerName != null) { - args[i] = resolveRequestHeader(headerName, required, defaultValue, methodParam, webRequest, handler); - } else if (requestBodyFound) { - args[i] = resolveRequestBody(methodParam, webRequest, handler); - } else if (cookieName != null) { - args[i] = resolveCookieValue(cookieName, required, defaultValue, methodParam, webRequest, handler); - } else if (pathVarName != null) { - args[i] = resolvePathVariable(pathVarName, methodParam, webRequest, handler); - } else if (attrName != null) { - WebDataBinder binder = - resolveModelAttribute(attrName, methodParam, implicitModel, webRequest, handler); - boolean assignBindingResult = (args.length > i + 1 && Errors.class.isAssignableFrom(paramTypes[i + 1])); - if (binder.getTarget() != null) { - doBind(binder, webRequest, validate, !assignBindingResult); - } - args[i] = binder.getTarget(); - if (assignBindingResult) { - args[i + 1] = binder.getBindingResult(); - i++; - } - implicitModel.putAll(binder.getBindingResult().getModel()); - } - } - - return args; - } - - protected void initBinder(Object handler, String attrName, WebDataBinder binder, NativeWebRequest webRequest) - throws Exception { - - if (this.bindingInitializer != null) { - this.bindingInitializer.initBinder(binder, webRequest); - } - if (handler != null) { - Set initBinderMethods = this.methodResolver.getInitBinderMethods(); - if (!initBinderMethods.isEmpty()) { - boolean debug = logger.isDebugEnabled(); - for (Method initBinderMethod : initBinderMethods) { - Method methodToInvoke = BridgeMethodResolver.findBridgedMethod(initBinderMethod); - String[] targetNames = AnnotationUtils.findAnnotation(initBinderMethod, InitBinder.class).value(); - if (targetNames.length == 0 || Arrays.asList(targetNames).contains(attrName)) { - Object[] initBinderArgs = - resolveInitBinderArguments(handler, methodToInvoke, binder, webRequest); - if (debug) { - logger.debug("Invoking init-binder method: " + methodToInvoke); - } - ReflectionUtils.makeAccessible(methodToInvoke); - Object returnValue = methodToInvoke.invoke(handler, initBinderArgs); - if (returnValue != null) { - throw new IllegalStateException( - "InitBinder methods must not have a return value: " + methodToInvoke); - } - } - } - } - } - } - - private Object[] resolveInitBinderArguments(Object handler, Method initBinderMethod, - WebDataBinder binder, NativeWebRequest webRequest) throws Exception { - - Class[] initBinderParams = initBinderMethod.getParameterTypes(); - Object[] initBinderArgs = new Object[initBinderParams.length]; - - for (int i = 0; i < initBinderArgs.length; i++) { - MethodParameter methodParam = new MethodParameter(initBinderMethod, i); - methodParam.initParameterNameDiscovery(this.parameterNameDiscoverer); - GenericTypeResolver.resolveParameterType(methodParam, handler.getClass()); - String paramName = null; - boolean paramRequired = false; - String paramDefaultValue = null; - String pathVarName = null; - Annotation[] paramAnns = methodParam.getParameterAnnotations(); - - for (Annotation paramAnn : paramAnns) { - if (RequestParam.class.isInstance(paramAnn)) { - RequestParam requestParam = (RequestParam) paramAnn; - paramName = requestParam.value(); - paramRequired = requestParam.required(); - paramDefaultValue = parseDefaultValueAttribute(requestParam.defaultValue()); - break; - } else if (ModelAttribute.class.isInstance(paramAnn)) { - throw new IllegalStateException( - "@ModelAttribute is not supported on @InitBinder methods: " + initBinderMethod); - } else if (PathVariable.class.isInstance(paramAnn)) { - PathVariable pathVar = (PathVariable) paramAnn; - pathVarName = pathVar.value(); - } - } - - if (paramName == null && pathVarName == null) { - Object argValue = resolveCommonArgument(methodParam, webRequest); - if (argValue != WebArgumentResolver.UNRESOLVED) { - initBinderArgs[i] = argValue; - } else { - Class paramType = initBinderParams[i]; - if (paramType.isInstance(binder)) { - initBinderArgs[i] = binder; - } else if (BeanUtils.isSimpleProperty(paramType)) { - paramName = ""; - } else { - throw new IllegalStateException("Unsupported argument [" + paramType.getName() + - "] for @InitBinder method: " + initBinderMethod); - } - } - } - - if (paramName != null) { - initBinderArgs[i] = - resolveRequestParam(paramName, paramRequired, paramDefaultValue, methodParam, webRequest, null); - } else if (pathVarName != null) { - initBinderArgs[i] = resolvePathVariable(pathVarName, methodParam, webRequest, null); - } - } - - return initBinderArgs; - } - - @SuppressWarnings("unchecked") - private Object resolveRequestParam(String paramName, boolean required, String defaultValue, - MethodParameter methodParam, NativeWebRequest webRequest, Object handlerForInitBinderCall) - throws Exception { - - Class paramType = methodParam.getParameterType(); - if (Map.class.isAssignableFrom(paramType) && paramName.length() == 0) { - return resolveRequestParamMap((Class) paramType, webRequest); - } - if (paramName.length() == 0) { - paramName = getRequiredParameterName(methodParam); - } - Object paramValue = null; - MultipartRequest multipartRequest = webRequest.getNativeRequest(MultipartRequest.class); - if (multipartRequest != null) { - List files = multipartRequest.getFiles(paramName); - if (!files.isEmpty()) { - if (files.size() == 1 && !paramType.isArray() && !Collection.class.isAssignableFrom(paramType)) { - paramValue = files.get(0); - } else { - paramValue = files; - } - } - } - if (paramValue == null) { - String[] paramValues = webRequest.getParameterValues(paramName); - if (paramValues != null) { - if (paramValues.length == 1 && !paramType.isArray() && !Collection.class.isAssignableFrom(paramType)) { - paramValue = paramValues[0]; - } else { - paramValue = paramValues; - } - } - } - if (paramValue == null) { - if (defaultValue != null) { - paramValue = resolveDefaultValue(defaultValue); - } else if (required) { - raiseMissingParameterException(paramName, paramType); - } - paramValue = checkValue(paramName, paramValue, paramType); - } - WebDataBinder binder = createBinder(webRequest, null, paramName); - initBinder(handlerForInitBinderCall, paramName, binder, webRequest); - return binder.convertIfNecessary(paramValue, paramType, methodParam); - } - - private Map resolveRequestParamMap(Class mapType, NativeWebRequest webRequest) { - Map parameterMap = webRequest.getParameterMap(); - if (MultiValueMap.class.isAssignableFrom(mapType)) { - MultiValueMap result = new LinkedMultiValueMap(parameterMap.size()); - for (Map.Entry entry : parameterMap.entrySet()) { - for (String value : entry.getValue()) { - result.add(entry.getKey(), value); - } - } - return result; - } else { - Map result = new LinkedHashMap(parameterMap.size()); - for (Map.Entry entry : parameterMap.entrySet()) { - if (entry.getValue().length > 0) { - result.put(entry.getKey(), entry.getValue()[0]); - } - } - return result; - } - } - - @SuppressWarnings("unchecked") - private Object resolveRequestHeader(String headerName, boolean required, String defaultValue, - MethodParameter methodParam, NativeWebRequest webRequest, Object handlerForInitBinderCall) - throws Exception { - - Class paramType = methodParam.getParameterType(); - if (Map.class.isAssignableFrom(paramType)) { - return resolveRequestHeaderMap((Class) paramType, webRequest); - } - if (headerName.length() == 0) { - headerName = getRequiredParameterName(methodParam); - } - Object headerValue = null; - String[] headerValues = webRequest.getHeaderValues(headerName); - if (headerValues != null) { - headerValue = (headerValues.length == 1 ? headerValues[0] : headerValues); - } - if (headerValue == null) { - if (defaultValue != null) { - headerValue = resolveDefaultValue(defaultValue); - } else if (required) { - raiseMissingHeaderException(headerName, paramType); - } - headerValue = checkValue(headerName, headerValue, paramType); - } - WebDataBinder binder = createBinder(webRequest, null, headerName); - initBinder(handlerForInitBinderCall, headerName, binder, webRequest); - return binder.convertIfNecessary(headerValue, paramType, methodParam); - } - - private Map resolveRequestHeaderMap(Class mapType, NativeWebRequest webRequest) { - if (MultiValueMap.class.isAssignableFrom(mapType)) { - MultiValueMap result; - if (HttpHeaders.class.isAssignableFrom(mapType)) { - result = new HttpHeaders(); - } else { - result = new LinkedMultiValueMap(); - } - for (Iterator iterator = webRequest.getHeaderNames(); iterator.hasNext();) { - String headerName = iterator.next(); - for (String headerValue : webRequest.getHeaderValues(headerName)) { - result.add(headerName, headerValue); - } - } - return result; - } else { - Map result = new LinkedHashMap(); - for (Iterator iterator = webRequest.getHeaderNames(); iterator.hasNext();) { - String headerName = iterator.next(); - String headerValue = webRequest.getHeader(headerName); - result.put(headerName, headerValue); - } - return result; - } - } - - /** - * Resolves the given {@link RequestBody @RequestBody} annotation. - */ - protected Object resolveRequestBody(MethodParameter methodParam, NativeWebRequest webRequest, Object handler) - throws Exception { - - return readWithMessageConverters(methodParam, createHttpInputMessage(webRequest), methodParam.getParameterType()); - } - - private HttpEntity resolveHttpEntityRequest(MethodParameter methodParam, NativeWebRequest webRequest) - throws Exception { - - HttpInputMessage inputMessage = createHttpInputMessage(webRequest); - Class paramType = getHttpEntityType(methodParam); - Object body = readWithMessageConverters(methodParam, inputMessage, paramType); - return new HttpEntity(body, inputMessage.getHeaders()); - } - - private Object readWithMessageConverters(MethodParameter methodParam, HttpInputMessage inputMessage, Class paramType) - throws Exception { - - MediaType contentType = inputMessage.getHeaders().getContentType(); - if (contentType == null) { - StringBuilder builder = new StringBuilder(ClassUtils.getShortName(methodParam.getParameterType())); - String paramName = methodParam.getParameterName(); - if (paramName != null) { - builder.append(' '); - builder.append(paramName); - } - throw new HttpMediaTypeNotSupportedException( - "Cannot extract parameter (" + builder.toString() + "): no Content-Type found"); - } - - List allSupportedMediaTypes = new ArrayList(); - if (this.messageConverters != null) { - for (HttpMessageConverter messageConverter : this.messageConverters) { - allSupportedMediaTypes.addAll(messageConverter.getSupportedMediaTypes()); - if (messageConverter.canRead(paramType, contentType)) { - if (logger.isDebugEnabled()) { - logger.debug("Reading [" + paramType.getName() + "] as \"" + contentType - + "\" using [" + messageConverter + "]"); - } - return messageConverter.read(paramType, inputMessage); - } - } - } - throw new HttpMediaTypeNotSupportedException(contentType, allSupportedMediaTypes); - } - - private Class getHttpEntityType(MethodParameter methodParam) { - Assert.isAssignable(HttpEntity.class, methodParam.getParameterType()); - ParameterizedType type = (ParameterizedType) methodParam.getGenericParameterType(); - if (type.getActualTypeArguments().length == 1) { - Type typeArgument = type.getActualTypeArguments()[0]; - if (typeArgument instanceof Class) { - return (Class) typeArgument; - } else if (typeArgument instanceof GenericArrayType) { - Type componentType = ((GenericArrayType) typeArgument).getGenericComponentType(); - if (componentType instanceof Class) { - // Surely, there should be a nicer way to do this - Object array = Array.newInstance((Class) componentType, 0); - return array.getClass(); - } - } - } - throw new IllegalArgumentException( - "HttpEntity parameter (" + methodParam.getParameterName() + ") is not parameterized"); - - } - - private Object resolveCookieValue(String cookieName, boolean required, String defaultValue, - MethodParameter methodParam, NativeWebRequest webRequest, Object handlerForInitBinderCall) - throws Exception { - - Class paramType = methodParam.getParameterType(); - if (cookieName.length() == 0) { - cookieName = getRequiredParameterName(methodParam); - } - Object cookieValue = resolveCookieValue(cookieName, paramType, webRequest); - if (cookieValue == null) { - if (defaultValue != null) { - cookieValue = resolveDefaultValue(defaultValue); - } else if (required) { - raiseMissingCookieException(cookieName, paramType); - } - cookieValue = checkValue(cookieName, cookieValue, paramType); - } - WebDataBinder binder = createBinder(webRequest, null, cookieName); - initBinder(handlerForInitBinderCall, cookieName, binder, webRequest); - return binder.convertIfNecessary(cookieValue, paramType, methodParam); - } - - /** - * Resolves the given {@link CookieValue @CookieValue} annotation. - *

    Throws an UnsupportedOperationException by default. - */ - protected Object resolveCookieValue(String cookieName, Class paramType, NativeWebRequest webRequest) - throws Exception { - - throw new UnsupportedOperationException("@CookieValue not supported"); - } - - private Object resolvePathVariable(String pathVarName, MethodParameter methodParam, - NativeWebRequest webRequest, Object handlerForInitBinderCall) throws Exception { - - Class paramType = methodParam.getParameterType(); - if (pathVarName.length() == 0) { - pathVarName = getRequiredParameterName(methodParam); - } - String pathVarValue = resolvePathVariable(pathVarName, paramType, webRequest); - WebDataBinder binder = createBinder(webRequest, null, pathVarName); - initBinder(handlerForInitBinderCall, pathVarName, binder, webRequest); - return binder.convertIfNecessary(pathVarValue, paramType, methodParam); - } - - /** - * Resolves the given {@link PathVariable @PathVariable} annotation. - *

    Throws an UnsupportedOperationException by default. - */ - protected String resolvePathVariable(String pathVarName, Class paramType, NativeWebRequest webRequest) - throws Exception { - - throw new UnsupportedOperationException("@PathVariable not supported"); - } - - private String getRequiredParameterName(MethodParameter methodParam) { - String name = methodParam.getParameterName(); - if (name == null) { - throw new IllegalStateException( - "No parameter name specified for argument of type [" + methodParam.getParameterType().getName() + - "], and no parameter name information found in class file either."); - } - return name; - } - - private Object checkValue(String name, Object value, Class paramType) { - if (value == null) { - if (boolean.class.equals(paramType)) { - return Boolean.FALSE; - } else if (paramType.isPrimitive()) { - throw new IllegalStateException("Optional " + paramType + " parameter '" + name + - "' is not present but cannot be translated into a null value due to being declared as a " + - "primitive type. Consider declaring it as object wrapper for the corresponding primitive type."); - } - } - return value; - } - - private WebDataBinder resolveModelAttribute(String attrName, MethodParameter methodParam, - ExtendedModelMap implicitModel, NativeWebRequest webRequest, Object handler) throws Exception { - - // Bind request parameter onto object... - String name = attrName; - if ("".equals(name)) { - name = Conventions.getVariableNameForParameter(methodParam); - } - Class paramType = methodParam.getParameterType(); - Object bindObject; - if (implicitModel.containsKey(name)) { - bindObject = implicitModel.get(name); - } else if (this.methodResolver.isSessionAttribute(name, paramType)) { - bindObject = this.sessionAttributeStore.retrieveAttribute(webRequest, name); - if (bindObject == null) { - raiseSessionRequiredException("Session attribute '" + name + "' required - not found in session"); - } - } else { - bindObject = BeanUtils.instantiateClass(paramType); - } - WebDataBinder binder = createBinder(webRequest, bindObject, name); - initBinder(handler, name, binder, webRequest); - return binder; - } - - - /** - * Determine whether the given value qualifies as a "binding candidate", i.e. might potentially be subject to - * bean-style data binding later on. - */ - protected boolean isBindingCandidate(Object value) { - return (value != null && !value.getClass().isArray() && !(value instanceof Collection) && - !(value instanceof Map) && !BeanUtils.isSimpleValueType(value.getClass())); - } - - protected void raiseMissingParameterException(String paramName, Class paramType) throws Exception { - throw new IllegalStateException("Missing parameter '" + paramName + "' of type [" + paramType.getName() + "]"); - } - - protected void raiseMissingHeaderException(String headerName, Class paramType) throws Exception { - throw new IllegalStateException("Missing header '" + headerName + "' of type [" + paramType.getName() + "]"); - } - - protected void raiseMissingCookieException(String cookieName, Class paramType) throws Exception { - throw new IllegalStateException( - "Missing cookie value '" + cookieName + "' of type [" + paramType.getName() + "]"); - } - - protected void raiseSessionRequiredException(String message) throws Exception { - throw new IllegalStateException(message); - } - - protected WebDataBinder createBinder(NativeWebRequest webRequest, Object target, String objectName) - throws Exception { - - return new WebRequestDataBinder(target, objectName); - } - - private void doBind(WebDataBinder binder, NativeWebRequest webRequest, boolean validate, boolean failOnErrors) - throws Exception { - - doBind(binder, webRequest); - if (validate) { - binder.validate(); - } - if (failOnErrors && binder.getBindingResult().hasErrors()) { - throw new BindException(binder.getBindingResult()); - } - } - - protected void doBind(WebDataBinder binder, NativeWebRequest webRequest) throws Exception { - ((WebRequestDataBinder) binder).bind(webRequest); - } - - /** - * Return a {@link HttpInputMessage} for the given {@link NativeWebRequest}. - *

    Throws an UnsupportedOperation1Exception by default. - */ - protected HttpInputMessage createHttpInputMessage(NativeWebRequest webRequest) throws Exception { - throw new UnsupportedOperationException("@RequestBody not supported"); - } - - /** - * Return a {@link HttpOutputMessage} for the given {@link NativeWebRequest}. - *

    Throws an UnsupportedOperationException by default. - */ - protected HttpOutputMessage createHttpOutputMessage(NativeWebRequest webRequest) throws Exception { - throw new UnsupportedOperationException("@ResponseBody not supported"); - } - - protected String parseDefaultValueAttribute(String value) { - return (ValueConstants.DEFAULT_NONE.equals(value) ? null : value); - } - - protected Object resolveDefaultValue(String value) { - return value; - } - - protected Object resolveCommonArgument(MethodParameter methodParameter, NativeWebRequest webRequest) - throws Exception { - - // Invoke custom argument resolvers if present... - if (this.customArgumentResolvers != null) { - for (WebArgumentResolver argumentResolver : this.customArgumentResolvers) { - Object value = argumentResolver.resolveArgument(methodParameter, webRequest); - if (value != WebArgumentResolver.UNRESOLVED) { - return value; - } - } - } - - // Resolution of standard parameter types... - Class paramType = methodParameter.getParameterType(); - Object value = resolveStandardArgument(paramType, webRequest); - if (value != WebArgumentResolver.UNRESOLVED && !ClassUtils.isAssignableValue(paramType, value)) { - throw new IllegalStateException("Standard argument type [" + paramType.getName() + - "] resolved to incompatible value of type [" + (value != null ? value.getClass() : null) + - "]. Consider declaring the argument type in a less specific fashion."); - } - return value; - } - - protected Object resolveStandardArgument(Class parameterType, NativeWebRequest webRequest) throws Exception { - if (WebRequest.class.isAssignableFrom(parameterType)) { - return webRequest; - } - return WebArgumentResolver.UNRESOLVED; - } - - protected final void addReturnValueAsModelAttribute(Method handlerMethod, Class handlerType, - Object returnValue, ExtendedModelMap implicitModel) { - - ModelAttribute attr = AnnotationUtils.findAnnotation(handlerMethod, ModelAttribute.class); - String attrName = (attr != null ? attr.value() : ""); - if ("".equals(attrName)) { - Class resolvedType = GenericTypeResolver.resolveReturnType(handlerMethod, handlerType); - attrName = Conventions.getVariableNameForReturnType(handlerMethod, resolvedType, returnValue); - } - implicitModel.addAttribute(attrName, returnValue); - } - -}