diff --git a/spring-web/src/main/java/org/springframework/web/method/annotation/ModelAttributeMethodProcessor.java b/spring-web/src/main/java/org/springframework/web/method/annotation/ModelAttributeMethodProcessor.java index d2e25293603..e2ae411e82e 100644 --- a/spring-web/src/main/java/org/springframework/web/method/annotation/ModelAttributeMethodProcessor.java +++ b/spring-web/src/main/java/org/springframework/web/method/annotation/ModelAttributeMethodProcessor.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2012 the original author or authors. + * Copyright 2002-2015 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. @@ -21,6 +21,7 @@ import java.util.Map; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; + import org.springframework.beans.BeanUtils; import org.springframework.core.MethodParameter; import org.springframework.core.annotation.AnnotationUtils; @@ -54,10 +55,11 @@ import org.springframework.web.method.support.ModelAndViewContainer; */ public class ModelAttributeMethodProcessor implements HandlerMethodArgumentResolver, HandlerMethodReturnValueHandler { - protected Log logger = LogFactory.getLog(this.getClass()); + protected final Log logger = LogFactory.getLog(getClass()); private final boolean annotationNotRequired; + /** * @param annotationNotRequired if "true", non-simple method arguments and * return values are considered model attributes with or without a @@ -67,10 +69,12 @@ public class ModelAttributeMethodProcessor implements HandlerMethodArgumentResol this.annotationNotRequired = annotationNotRequired; } + /** - * @return true if the parameter is annotated with {@link ModelAttribute} - * or in default resolution mode also if it is not a simple type. + * Returns {@code true} if the parameter is annotated with {@link ModelAttribute} + * or in default resolution mode, and also if it is not a simple type. */ + @Override public boolean supportsParameter(MethodParameter parameter) { if (parameter.hasParameterAnnotation(ModelAttribute.class)) { return true; @@ -92,18 +96,16 @@ public class ModelAttributeMethodProcessor implements HandlerMethodArgumentResol * and the next method parameter is not of type {@link Errors}. * @throws Exception if WebDataBinder initialization fails. */ - public final Object resolveArgument( - MethodParameter parameter, ModelAndViewContainer mavContainer, - NativeWebRequest request, WebDataBinderFactory binderFactory) - throws Exception { + public final Object resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer, + NativeWebRequest webRequest, WebDataBinderFactory binderFactory) throws Exception { String name = ModelFactory.getNameForParameter(parameter); - Object attribute = (mavContainer.containsAttribute(name)) ? - mavContainer.getModel().get(name) : createAttribute(name, parameter, binderFactory, request); + Object attribute = (mavContainer.containsAttribute(name) ? + mavContainer.getModel().get(name) : createAttribute(name, parameter, binderFactory, webRequest)); - WebDataBinder binder = binderFactory.createBinder(request, attribute, name); + WebDataBinder binder = binderFactory.createBinder(webRequest, attribute, name); if (binder.getTarget() != null) { - bindRequestParameters(binder, request); + bindRequestParameters(binder, webRequest); validateIfApplicable(binder, parameter); if (binder.getBindingResult().hasErrors()) { if (isBindExceptionRequired(binder, parameter)) { @@ -113,7 +115,6 @@ public class ModelAttributeMethodProcessor implements HandlerMethodArgumentResol } // Add resolved attribute and BindingResult at the end of the model - Map bindingResultModel = binder.getBindingResult().getModel(); mavContainer.removeAttributes(bindingResultModel); mavContainer.addAllAttributes(bindingResultModel); @@ -124,16 +125,16 @@ public class ModelAttributeMethodProcessor implements HandlerMethodArgumentResol /** * Extension point to create the model attribute if not found in the model. * The default implementation uses the default constructor. - * @param attributeName the name of the attribute, never {@code null} - * @param parameter the method parameter + * @param attributeName the name of the attribute (never {@code null}) + * @param methodParam the method parameter * @param binderFactory for creating WebDataBinder instance * @param request the current request - * @return the created model attribute, never {@code null} + * @return the created model attribute (never {@code null}) */ - protected Object createAttribute(String attributeName, MethodParameter parameter, - WebDataBinderFactory binderFactory, NativeWebRequest request) throws Exception { + protected Object createAttribute(String attributeName, MethodParameter methodParam, + WebDataBinderFactory binderFactory, NativeWebRequest request) throws Exception { - return BeanUtils.instantiateClass(parameter.getParameterType()); + return BeanUtils.instantiateClass(methodParam.getParameterType()); } /** @@ -147,15 +148,17 @@ public class ModelAttributeMethodProcessor implements HandlerMethodArgumentResol /** * Validate the model attribute if applicable. - *

The default implementation checks for {@code @javax.validation.Valid}. + *

The default implementation checks for {@code @javax.validation.Valid}, + * Spring's {@link org.springframework.validation.annotation.Validated}, + * and custom annotations whose name starts with "Valid". * @param binder the DataBinder to be used - * @param parameter the method parameter + * @param methodParam the method parameter */ - protected void validateIfApplicable(WebDataBinder binder, MethodParameter parameter) { - Annotation[] annotations = parameter.getParameterAnnotations(); - for (Annotation annot : annotations) { - if (annot.annotationType().getSimpleName().startsWith("Valid")) { - Object hints = AnnotationUtils.getValue(annot); + protected void validateIfApplicable(WebDataBinder binder, MethodParameter methodParam) { + Annotation[] annotations = methodParam.getParameterAnnotations(); + for (Annotation ann : annotations) { + if (ann.annotationType().getSimpleName().startsWith("Valid")) { + Object hints = AnnotationUtils.getValue(ann); binder.validate(hints instanceof Object[] ? (Object[]) hints : new Object[] {hints}); break; } @@ -165,14 +168,13 @@ public class ModelAttributeMethodProcessor implements HandlerMethodArgumentResol /** * Whether to raise a {@link BindException} on validation errors. * @param binder the data binder used to perform data binding - * @param parameter the method argument - * @return {@code true} if the next method argument is not of type {@link Errors}. + * @param methodParam the method argument + * @return {@code true} if the next method argument is not of type {@link Errors} */ - protected boolean isBindExceptionRequired(WebDataBinder binder, MethodParameter parameter) { - int i = parameter.getParameterIndex(); - Class[] paramTypes = parameter.getMethod().getParameterTypes(); + protected boolean isBindExceptionRequired(WebDataBinder binder, MethodParameter methodParam) { + int i = methodParam.getParameterIndex(); + Class[] paramTypes = methodParam.getMethod().getParameterTypes(); boolean hasBindingResult = (paramTypes.length > (i + 1) && Errors.class.isAssignableFrom(paramTypes[i + 1])); - return !hasBindingResult; } @@ -195,14 +197,13 @@ public class ModelAttributeMethodProcessor implements HandlerMethodArgumentResol /** * Add non-null return values to the {@link ModelAndViewContainer}. */ - public void handleReturnValue( - Object returnValue, MethodParameter returnType, - ModelAndViewContainer mavContainer, NativeWebRequest webRequest) - throws Exception { + public void handleReturnValue(Object returnValue, MethodParameter returnType, + ModelAndViewContainer mavContainer, NativeWebRequest webRequest) throws Exception { if (returnValue != null) { String name = ModelFactory.getNameForReturnValue(returnValue, returnType); mavContainer.addAttribute(name, returnValue); } } + } diff --git a/spring-webmvc/src/main/java/org/springframework/web/servlet/mvc/method/annotation/AbstractMessageConverterMethodArgumentResolver.java b/spring-webmvc/src/main/java/org/springframework/web/servlet/mvc/method/annotation/AbstractMessageConverterMethodArgumentResolver.java index 519ae72967d..211cb919889 100644 --- a/spring-webmvc/src/main/java/org/springframework/web/servlet/mvc/method/annotation/AbstractMessageConverterMethodArgumentResolver.java +++ b/spring-webmvc/src/main/java/org/springframework/web/servlet/mvc/method/annotation/AbstractMessageConverterMethodArgumentResolver.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2012 the original author or authors. + * Copyright 2002-2015 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. @@ -25,11 +25,11 @@ import java.util.LinkedHashSet; import java.util.List; import java.util.Map; import java.util.Set; - import javax.servlet.http.HttpServletRequest; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; + import org.springframework.core.GenericTypeResolver; import org.springframework.core.MethodParameter; import org.springframework.http.HttpInputMessage; @@ -59,12 +59,14 @@ public abstract class AbstractMessageConverterMethodArgumentResolver implements protected final List allSupportedMediaTypes; + public AbstractMessageConverterMethodArgumentResolver(List> messageConverters) { Assert.notEmpty(messageConverters, "'messageConverters' must not be empty"); this.messageConverters = messageConverters; this.allSupportedMediaTypes = getAllSupportedMediaTypes(messageConverters); } + /** * Return the media types supported by all provided message converters sorted * by specificity via {@link MediaType#sortBySpecificity(List)}. @@ -79,10 +81,10 @@ public abstract class AbstractMessageConverterMethodArgumentResolver implements return Collections.unmodifiableList(result); } + /** - * Creates the method argument value of the expected parameter type by + * Create the method argument value of the expected parameter type by * reading from the given request. - * * @param the expected type of the argument value to be created * @param webRequest the current request * @param methodParam the method argument @@ -99,9 +101,8 @@ public abstract class AbstractMessageConverterMethodArgumentResolver implements } /** - * Creates the method argument value of the expected parameter type by reading + * Create the method argument value of the expected parameter type by reading * from the given HttpInputMessage. - * * @param the expected type of the argument value to be created * @param inputMessage the HTTP input message representing the current request * @param methodParam the method argument @@ -123,43 +124,41 @@ public abstract class AbstractMessageConverterMethodArgumentResolver implements catch (InvalidMediaTypeException ex) { throw new HttpMediaTypeNotSupportedException(ex.getMessage()); } - if (contentType == null) { contentType = MediaType.APPLICATION_OCTET_STREAM; } - Class contextClass = methodParam.getDeclaringClass(); - Map map = GenericTypeResolver.getTypeVariableMap(contextClass); - Class targetClass = (Class) GenericTypeResolver.resolveType(targetType, map); - - for (HttpMessageConverter converter : this.messageConverters) { - if (converter instanceof GenericHttpMessageConverter) { - GenericHttpMessageConverter genericConverter = (GenericHttpMessageConverter) converter; - if (genericConverter.canRead(targetType, contextClass, contentType)) { - if (logger.isDebugEnabled()) { - logger.debug("Reading [" + targetType + "] as \"" + - contentType + "\" using [" + converter + "]"); - } - return genericConverter.read(targetType, contextClass, inputMessage); - } + Class contextClass = methodParam.getDeclaringClass(); + Map map = GenericTypeResolver.getTypeVariableMap(contextClass); + Class targetClass = (Class) GenericTypeResolver.resolveType(targetType, map); + + for (HttpMessageConverter converter : this.messageConverters) { + if (converter instanceof GenericHttpMessageConverter) { + GenericHttpMessageConverter genericConverter = (GenericHttpMessageConverter) converter; + if (genericConverter.canRead(targetType, contextClass, contentType)) { + if (logger.isDebugEnabled()) { + logger.debug("Reading [" + targetType + "] as \"" + + contentType + "\" using [" + converter + "]"); } - if (targetClass != null) { - if (converter.canRead(targetClass, contentType)) { - if (logger.isDebugEnabled()) { - logger.debug("Reading [" + targetClass.getName() + "] as \"" + - contentType + "\" using [" + converter + "]"); - } - return ((HttpMessageConverter) converter).read(targetClass, inputMessage); - } + return genericConverter.read(targetType, contextClass, inputMessage); + } + } + if (targetClass != null) { + if (converter.canRead(targetClass, contentType)) { + if (logger.isDebugEnabled()) { + logger.debug("Reading [" + targetClass.getName() + "] as \"" + + contentType + "\" using [" + converter + "]"); } + return ((HttpMessageConverter) converter).read(targetClass, inputMessage); } - - throw new HttpMediaTypeNotSupportedException(contentType, allSupportedMediaTypes); } + } + + throw new HttpMediaTypeNotSupportedException(contentType, this.allSupportedMediaTypes); + } /** - * Creates a new {@link HttpInputMessage} from the given {@link NativeWebRequest}. - * + * Create a new {@link HttpInputMessage} from the given {@link NativeWebRequest}. * @param webRequest the web request to create an input message from * @return the input message */ diff --git a/spring-webmvc/src/main/java/org/springframework/web/servlet/mvc/method/annotation/RequestPartMethodArgumentResolver.java b/spring-webmvc/src/main/java/org/springframework/web/servlet/mvc/method/annotation/RequestPartMethodArgumentResolver.java index cea6c55783f..dc6fe4d3cf2 100644 --- a/spring-webmvc/src/main/java/org/springframework/web/servlet/mvc/method/annotation/RequestPartMethodArgumentResolver.java +++ b/spring-webmvc/src/main/java/org/springframework/web/servlet/mvc/method/annotation/RequestPartMethodArgumentResolver.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2011 the original author or authors. + * Copyright 2002-2015 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. @@ -49,18 +49,15 @@ import org.springframework.web.util.WebUtils; /** * Resolves the following method arguments: *

* - *

When a parameter is annotated with {@code @RequestPart} the content of the - * part is passed through an {@link HttpMessageConverter} to resolve the method - * argument with the 'Content-Type' of the request part in mind. This is - * analogous to what @{@link RequestBody} does to resolve an argument based on - * the content of a regular request. + *

When a parameter is annotated with {@code @RequestPart}, the content of the part is + * passed through an {@link HttpMessageConverter} to resolve the method argument with the + * 'Content-Type' of the request part in mind. This is analogous to what @{@link RequestBody} + * does to resolve an argument based on the content of a regular request. * *

When a parameter is not annotated or the name of the part is not specified, * it is derived from the name of the method argument. @@ -82,9 +79,9 @@ public class RequestPartMethodArgumentResolver extends AbstractMessageConverterM /** * Supports the following: *

*/ public boolean supportsParameter(MethodParameter parameter) { @@ -146,8 +143,8 @@ public class RequestPartMethodArgumentResolver extends AbstractMessageConverterM } } - RequestPart annot = parameter.getParameterAnnotation(RequestPart.class); - boolean isRequired = (annot == null || annot.required()); + RequestPart ann = parameter.getParameterAnnotation(RequestPart.class); + boolean isRequired = (ann == null || ann.required()); if (arg == null && isRequired) { throw new MissingServletRequestPartException(partName); @@ -163,39 +160,51 @@ public class RequestPartMethodArgumentResolver extends AbstractMessageConverterM } } - private String getPartName(MethodParameter parameter) { - RequestPart annot = parameter.getParameterAnnotation(RequestPart.class); - String partName = (annot != null) ? annot.value() : ""; + private String getPartName(MethodParameter methodParam) { + RequestPart annot = methodParam.getParameterAnnotation(RequestPart.class); + String partName = (annot != null ? annot.value() : ""); if (partName.length() == 0) { - partName = parameter.getParameterName(); - Assert.notNull(partName, "Request part name for argument type [" + parameter.getParameterType().getName() - + "] not available, and parameter name information not found in class file either."); + partName = methodParam.getParameterName(); + if (partName == null) { + throw new IllegalArgumentException("Request part name for argument type [" + + methodParam.getNestedParameterType().getName() + + "] not specified, and parameter name information not found in class file either."); + } } return partName; } - private boolean isMultipartFileCollection(MethodParameter parameter) { - Class paramType = parameter.getParameterType(); + private boolean isMultipartFileCollection(MethodParameter methodParam) { + Class paramType = methodParam.getParameterType(); if (Collection.class.equals(paramType) || List.class.isAssignableFrom(paramType)){ - Class valueType = GenericCollectionTypeResolver.getCollectionParameterType(parameter); - if (valueType != null && valueType.equals(MultipartFile.class)) { + Class valueType = GenericCollectionTypeResolver.getCollectionParameterType(methodParam); + if (MultipartFile.class.equals(valueType)) { return true; } } return false; } - private void validate(WebDataBinder binder, MethodParameter parameter) throws MethodArgumentNotValidException { - - Annotation[] annotations = parameter.getParameterAnnotations(); - for (Annotation annot : annotations) { - if (annot.annotationType().getSimpleName().startsWith("Valid")) { - Object hints = AnnotationUtils.getValue(annot); + /** + * Validate the request part if applicable. + *

The default implementation checks for {@code @javax.validation.Valid}, + * Spring's {@link org.springframework.validation.annotation.Validated}, + * and custom annotations whose name starts with "Valid". + * @param binder the DataBinder to be used + * @param methodParam the method parameter + * @throws MethodArgumentNotValidException in case of a binding error which + * is meant to be fatal (i.e. without a declared {@link Errors} parameter) + */ + private void validate(WebDataBinder binder, MethodParameter methodParam) throws MethodArgumentNotValidException { + Annotation[] annotations = methodParam.getParameterAnnotations(); + for (Annotation ann : annotations) { + if (ann.annotationType().getSimpleName().startsWith("Valid")) { + Object hints = AnnotationUtils.getValue(ann); binder.validate(hints instanceof Object[] ? (Object[]) hints : new Object[] {hints}); BindingResult bindingResult = binder.getBindingResult(); if (bindingResult.hasErrors()) { - if (isBindExceptionRequired(binder, parameter)) { - throw new MethodArgumentNotValidException(parameter, bindingResult); + if (isBindExceptionRequired(binder, methodParam)) { + throw new MethodArgumentNotValidException(methodParam, bindingResult); } } } @@ -205,14 +214,13 @@ public class RequestPartMethodArgumentResolver extends AbstractMessageConverterM /** * Whether to raise a {@link MethodArgumentNotValidException} on validation errors. * @param binder the data binder used to perform data binding - * @param parameter the method argument - * @return {@code true} if the next method argument is not of type {@link Errors}. + * @param methodParam the method argument + * @return {@code true} if the next method argument is not of type {@link Errors} */ - private boolean isBindExceptionRequired(WebDataBinder binder, MethodParameter parameter) { - int i = parameter.getParameterIndex(); - Class[] paramTypes = parameter.getMethod().getParameterTypes(); + private boolean isBindExceptionRequired(WebDataBinder binder, MethodParameter methodParam) { + int i = methodParam.getParameterIndex(); + Class[] paramTypes = methodParam.getMethod().getParameterTypes(); boolean hasBindingResult = (paramTypes.length > (i + 1) && Errors.class.isAssignableFrom(paramTypes[i + 1])); - return !hasBindingResult; } diff --git a/spring-webmvc/src/main/java/org/springframework/web/servlet/mvc/method/annotation/RequestResponseBodyMethodProcessor.java b/spring-webmvc/src/main/java/org/springframework/web/servlet/mvc/method/annotation/RequestResponseBodyMethodProcessor.java index a7473a60f18..cf452d8d334 100644 --- a/spring-webmvc/src/main/java/org/springframework/web/servlet/mvc/method/annotation/RequestResponseBodyMethodProcessor.java +++ b/spring-webmvc/src/main/java/org/springframework/web/servlet/mvc/method/annotation/RequestResponseBodyMethodProcessor.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2012 the original author or authors. + * Copyright 2002-2015 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. @@ -22,7 +22,6 @@ import java.io.PushbackInputStream; import java.lang.annotation.Annotation; import java.lang.reflect.Type; import java.util.List; - import javax.servlet.http.HttpServletRequest; import org.springframework.core.Conventions; @@ -47,16 +46,14 @@ import org.springframework.web.method.support.ModelAndViewContainer; import org.springframework.web.servlet.mvc.support.DefaultHandlerExceptionResolver; /** - * Resolves method arguments annotated with {@code @RequestBody} and handles - * return values from methods annotated with {@code @ResponseBody} by reading - * and writing to the body of the request or response with an - * {@link HttpMessageConverter}. + * Resolves method arguments annotated with {@code @RequestBody} and handles return + * values from methods annotated with {@code @ResponseBody} by reading and writing + * to the body of the request or response with an {@link HttpMessageConverter}. * - *

An {@code @RequestBody} method argument is also validated if it is - * annotated with {@code @javax.validation.Valid}. In case of validation - * failure, {@link MethodArgumentNotValidException} is raised and results - * in a 400 response status code if {@link DefaultHandlerExceptionResolver} - * is configured. + *

An {@code @RequestBody} method argument is also validated if it is annotated + * with {@code @javax.validation.Valid}. In case of validation failure, + * {@link MethodArgumentNotValidException} is raised and results in a 400 response + * status code if {@link DefaultHandlerExceptionResolver} is configured. * * @author Arjen Poutsma * @author Rossen Stoyanchev @@ -74,49 +71,54 @@ public class RequestResponseBodyMethodProcessor extends AbstractMessageConverter super(messageConverters, contentNegotiationManager); } + public boolean supportsParameter(MethodParameter parameter) { return parameter.hasParameterAnnotation(RequestBody.class); } public boolean supportsReturnType(MethodParameter returnType) { - return returnType.getMethodAnnotation(ResponseBody.class) != null; + return (returnType.getMethodAnnotation(ResponseBody.class) != null); } /** - * {@inheritDoc} - * @throws MethodArgumentNotValidException if validation fails + * Throws MethodArgumentNotValidException if validation fails. * @throws HttpMessageNotReadableException if {@link RequestBody#required()} - * is {@code true} and there is no body content or if there is no suitable - * converter to read the content with. + * is {@code true} and there is no body content or if there is no suitable + * converter to read the content with. */ public Object resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer, NativeWebRequest webRequest, WebDataBinderFactory binderFactory) throws Exception { Object argument = readWithMessageConverters(webRequest, parameter, parameter.getGenericParameterType()); - String name = Conventions.getVariableNameForParameter(parameter); WebDataBinder binder = binderFactory.createBinder(webRequest, argument, name); - if (argument != null) { validate(binder, parameter); } - mavContainer.addAttribute(BindingResult.MODEL_KEY_PREFIX + name, binder.getBindingResult()); - return argument; } - private void validate(WebDataBinder binder, MethodParameter parameter) throws Exception, MethodArgumentNotValidException { - - Annotation[] annotations = parameter.getParameterAnnotations(); - for (Annotation annot : annotations) { - if (annot.annotationType().getSimpleName().startsWith("Valid")) { - Object hints = AnnotationUtils.getValue(annot); + /** + * Validate the request part if applicable. + *

The default implementation checks for {@code @javax.validation.Valid}, + * Spring's {@link org.springframework.validation.annotation.Validated}, + * and custom annotations whose name starts with "Valid". + * @param binder the DataBinder to be used + * @param methodParam the method parameter + * @throws MethodArgumentNotValidException in case of a binding error which + * is meant to be fatal (i.e. without a declared {@link Errors} parameter) + */ + private void validate(WebDataBinder binder, MethodParameter methodParam) throws MethodArgumentNotValidException { + Annotation[] annotations = methodParam.getParameterAnnotations(); + for (Annotation ann : annotations) { + if (ann.annotationType().getSimpleName().startsWith("Valid")) { + Object hints = AnnotationUtils.getValue(ann); binder.validate(hints instanceof Object[] ? (Object[]) hints : new Object[] {hints}); BindingResult bindingResult = binder.getBindingResult(); if (bindingResult.hasErrors()) { - if (isBindExceptionRequired(binder, parameter)) { - throw new MethodArgumentNotValidException(parameter, bindingResult); + if (isBindExceptionRequired(binder, methodParam)) { + throw new MethodArgumentNotValidException(methodParam, bindingResult); } } break; @@ -127,26 +129,25 @@ public class RequestResponseBodyMethodProcessor extends AbstractMessageConverter /** * Whether to raise a {@link MethodArgumentNotValidException} on validation errors. * @param binder the data binder used to perform data binding - * @param parameter the method argument - * @return {@code true} if the next method argument is not of type {@link Errors}. + * @param methodParam the method argument + * @return {@code true} if the next method argument is not of type {@link Errors} */ - private boolean isBindExceptionRequired(WebDataBinder binder, MethodParameter parameter) { - int i = parameter.getParameterIndex(); - Class[] paramTypes = parameter.getMethod().getParameterTypes(); + private boolean isBindExceptionRequired(WebDataBinder binder, MethodParameter methodParam) { + int i = methodParam.getParameterIndex(); + Class[] paramTypes = methodParam.getMethod().getParameterTypes(); boolean hasBindingResult = (paramTypes.length > (i + 1) && Errors.class.isAssignableFrom(paramTypes[i + 1])); - return !hasBindingResult; } @Override - protected Object readWithMessageConverters(NativeWebRequest webRequest, - MethodParameter methodParam, Type paramType) throws IOException, HttpMediaTypeNotSupportedException { + protected Object readWithMessageConverters(NativeWebRequest webRequest, MethodParameter methodParam, + Type paramType) throws IOException, HttpMediaTypeNotSupportedException { final HttpServletRequest servletRequest = webRequest.getNativeRequest(HttpServletRequest.class); HttpInputMessage inputMessage = new ServletServerHttpRequest(servletRequest); - RequestBody annot = methodParam.getParameterAnnotation(RequestBody.class); - if (!annot.required()) { + RequestBody ann = methodParam.getParameterAnnotation(RequestBody.class); + if (!ann.required()) { InputStream inputStream = inputMessage.getBody(); if (inputStream == null) { return null; diff --git a/spring-webmvc/src/main/java/org/springframework/web/servlet/mvc/method/annotation/ServletModelAttributeMethodProcessor.java b/spring-webmvc/src/main/java/org/springframework/web/servlet/mvc/method/annotation/ServletModelAttributeMethodProcessor.java index 3cfd087e334..6fcea9d5489 100644 --- a/spring-webmvc/src/main/java/org/springframework/web/servlet/mvc/method/annotation/ServletModelAttributeMethodProcessor.java +++ b/spring-webmvc/src/main/java/org/springframework/web/servlet/mvc/method/annotation/ServletModelAttributeMethodProcessor.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2012 the original author or authors. + * Copyright 2002-2015 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. @@ -18,7 +18,6 @@ package org.springframework.web.servlet.mvc.method.annotation; import java.util.Collections; import java.util.Map; - import javax.servlet.ServletRequest; import org.springframework.core.MethodParameter; @@ -36,7 +35,7 @@ import org.springframework.web.method.annotation.ModelAttributeMethodProcessor; import org.springframework.web.servlet.HandlerMapping; /** - * A Servlet-specific {@link org.springframework.web.method.annotation.ModelAttributeMethodProcessor} that applies data + * A Servlet-specific {@link ModelAttributeMethodProcessor} that applies data * binding through a WebDataBinder of type {@link ServletRequestDataBinder}. * *

Also adds a fall-back strategy to instantiate the model attribute from a @@ -51,34 +50,34 @@ public class ServletModelAttributeMethodProcessor extends ModelAttributeMethodPr /** * @param annotationNotRequired if "true", non-simple method arguments and * return values are considered model attributes with or without a - * {@code @ModelAttribute} annotation. + * {@code @ModelAttribute} annotation */ public ServletModelAttributeMethodProcessor(boolean annotationNotRequired) { super(annotationNotRequired); } + /** * Instantiate the model attribute from a URI template variable or from a * request parameter if the name matches to the model attribute name and * if there is an appropriate type conversion strategy. If none of these * are true delegate back to the base class. - * @see #createAttributeFromRequestValue(String, String, MethodParameter, WebDataBinderFactory, NativeWebRequest) + * @see #createAttributeFromRequestValue */ @Override - protected final Object createAttribute(String attributeName, - MethodParameter parameter, - WebDataBinderFactory binderFactory, - NativeWebRequest request) throws Exception { + protected final Object createAttribute(String attributeName, MethodParameter methodParam, + WebDataBinderFactory binderFactory, NativeWebRequest request) throws Exception { String value = getRequestValueForAttribute(attributeName, request); if (value != null) { - Object attribute = createAttributeFromRequestValue(value, attributeName, parameter, binderFactory, request); + Object attribute = createAttributeFromRequestValue( + value, attributeName, methodParam, binderFactory, request); if (attribute != null) { return attribute; } } - return super.createAttribute(attributeName, parameter, binderFactory, request); + return super.createAttribute(attributeName, methodParam, binderFactory, request); } /** @@ -105,10 +104,9 @@ public class ServletModelAttributeMethodProcessor extends ModelAttributeMethodPr @SuppressWarnings("unchecked") protected final Map getUriTemplateVariables(NativeWebRequest request) { - Map variables = - (Map) request.getAttribute( - HandlerMapping.URI_TEMPLATE_VARIABLES_ATTRIBUTE, RequestAttributes.SCOPE_REQUEST); - return (variables != null) ? variables : Collections.emptyMap(); + Map variables = (Map) request.getAttribute( + HandlerMapping.URI_TEMPLATE_VARIABLES_ATTRIBUTE, RequestAttributes.SCOPE_REQUEST); + return (variables != null ? variables : Collections.emptyMap()); } /** @@ -118,32 +116,31 @@ public class ServletModelAttributeMethodProcessor extends ModelAttributeMethodPr * {@link Converter} that can perform the conversion. * @param sourceValue the source value to create the model attribute from * @param attributeName the name of the attribute, never {@code null} - * @param parameter the method parameter + * @param methodParam the method parameter * @param binderFactory for creating WebDataBinder instance * @param request the current request * @return the created model attribute, or {@code null} * @throws Exception */ - protected Object createAttributeFromRequestValue(String sourceValue, - String attributeName, - MethodParameter parameter, - WebDataBinderFactory binderFactory, - NativeWebRequest request) throws Exception { + protected Object createAttributeFromRequestValue(String sourceValue, String attributeName, + MethodParameter methodParam, WebDataBinderFactory binderFactory, NativeWebRequest request) + throws Exception { + DataBinder binder = binderFactory.createBinder(request, null, attributeName); ConversionService conversionService = binder.getConversionService(); if (conversionService != null) { TypeDescriptor source = TypeDescriptor.valueOf(String.class); - TypeDescriptor target = new TypeDescriptor(parameter); + TypeDescriptor target = new TypeDescriptor(methodParam); if (conversionService.canConvert(source, target)) { - return binder.convertIfNecessary(sourceValue, parameter.getParameterType(), parameter); + return binder.convertIfNecessary(sourceValue, methodParam.getParameterType(), methodParam); } } return null; } /** - * {@inheritDoc} - *

Downcast {@link WebDataBinder} to {@link ServletRequestDataBinder} before binding. + * This implementation downcasts {@link WebDataBinder} to + * {@link ServletRequestDataBinder} before binding. * @see ServletRequestDataBinderFactory */ @Override