For details on the syntax of the expressions see {@link RequestMapping#consumes()}. If the condition is
- * created with 0 producible media type expressions, it matches to every request.
+ *
For details on the syntax of the expressions see {@link RequestMapping#consumes()}.
+ * If the condition is created without media type expressions, it matches to every request.
*
- *
This request condition is also capable of parsing header expressions specifically selecting 'Accept' header
- * expressions and converting them to prodicuble media type expressions.
+ *
This request condition is also capable of parsing header expressions by selecting
+ * 'Accept' header expressions and converting them to prodicuble media type expressions.
*
* @author Arjen Poutsma
* @author Rossen Stoyanchev
diff --git a/org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/mvc/condition/RequestCondition.java b/org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/mvc/condition/RequestCondition.java
index 24c16bc7ce..caea6862d9 100644
--- a/org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/mvc/condition/RequestCondition.java
+++ b/org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/mvc/condition/RequestCondition.java
@@ -18,11 +18,14 @@ package org.springframework.web.servlet.mvc.condition;
import javax.servlet.http.HttpServletRequest;
+import org.springframework.web.bind.annotation.RequestMapping;
+
/**
* The contract for request conditions.
*
- *
Request conditions can be combined (e.g. type + method-level conditions), matched to a request,
- * or compared to each other to determine if one matches the request better.
+ *
Request conditions can be combined via {@link #combine(Object)}, matched to a request via
+ * {@link #getMatchingCondition(HttpServletRequest)}, and compared to each other via
+ * {@link #compareTo(Object, HttpServletRequest)} to determine which matches a request more closely.
*
* @param The type of objects that this RequestCondition can be compared to and combined with.
*
@@ -33,9 +36,10 @@ import javax.servlet.http.HttpServletRequest;
public interface RequestCondition {
/**
- * Defines the rules for combining "this" condition (i.e. the current instance) with another condition.
- *
Example: combine type- and method-level request mapping conditions.
+ * Defines the rules for combining this condition (i.e. the current instance) with another condition.
+ * For example combining type- and method-level {@link RequestMapping} conditions.
*
+ * @param other the condition to combine with.
* @returns a request condition instance that is the result of combining the two condition instances.
*/
T combine(T other);
@@ -50,9 +54,9 @@ public interface RequestCondition {
T getMatchingCondition(HttpServletRequest request);
/**
- * Compares "this" condition (i.e. the current instance) with another condition in the context of a request.
- *
Note: it is assumed both instances have been obtained via {@link #getMatchingCondition(HttpServletRequest)}
- * to ensure they have content relevant to current request only.
+ * Compares this condition to another condition in the context of a specific request. This method assumes
+ * both instances have been obtained via {@link #getMatchingCondition(HttpServletRequest)} to ensure they
+ * have content relevant to current request only.
*/
int compareTo(T other, HttpServletRequest request);
diff --git a/org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/mvc/method/annotation/ExceptionHandlerExceptionResolver.java b/org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/mvc/method/annotation/ExceptionHandlerExceptionResolver.java
index c0bbd8ca4f..28a1ade5e6 100644
--- a/org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/mvc/method/annotation/ExceptionHandlerExceptionResolver.java
+++ b/org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/mvc/method/annotation/ExceptionHandlerExceptionResolver.java
@@ -62,11 +62,10 @@ import org.springframework.web.servlet.mvc.method.annotation.support.ServletWebA
import org.springframework.web.servlet.mvc.method.annotation.support.ViewMethodReturnValueHandler;
/**
- * An {@link AbstractHandlerMethodExceptionResolver} that looks for an {@link ExceptionHandler}-annotated method
- * that can handle a thrown exception. If a match is found the exception-handling method is invoked to finish
- * processing the request.
+ * An {@link AbstractHandlerMethodExceptionResolver} that supports using {@link ExceptionHandler}-annotated methods
+ * to resolve exceptions.
*
- *
{@link ExceptionMethodMapping} is a key contributing class storing method-to-exception type mappings extracted
+ *
{@link ExceptionMethodMapping} is a key contributing class that stores method-to-exception mappings extracted
* from {@link ExceptionHandler} annotations or from the list of method arguments on the exception-handling method.
* {@link ExceptionMethodMapping} assists with actually locating a method for a thrown exception.
*
diff --git a/org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/mvc/method/annotation/RequestMappingHandlerAdapter.java b/org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/mvc/method/annotation/RequestMappingHandlerAdapter.java
index cc6e2db7ab..d8e839ffc7 100644
--- a/org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/mvc/method/annotation/RequestMappingHandlerAdapter.java
+++ b/org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/mvc/method/annotation/RequestMappingHandlerAdapter.java
@@ -22,6 +22,7 @@ import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
+
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
@@ -52,7 +53,6 @@ import org.springframework.web.bind.support.DefaultSessionAttributeStore;
import org.springframework.web.bind.support.SessionAttributeStore;
import org.springframework.web.bind.support.SessionStatus;
import org.springframework.web.bind.support.SimpleSessionStatus;
-import org.springframework.web.bind.support.WebArgumentResolver;
import org.springframework.web.bind.support.WebBindingInitializer;
import org.springframework.web.bind.support.WebDataBinderFactory;
import org.springframework.web.context.request.ServletWebRequest;
@@ -90,7 +90,6 @@ import org.springframework.web.servlet.mvc.method.annotation.support.ServletCook
import org.springframework.web.servlet.mvc.method.annotation.support.ServletModelAttributeMethodProcessor;
import org.springframework.web.servlet.mvc.method.annotation.support.ServletRequestMethodArgumentResolver;
import org.springframework.web.servlet.mvc.method.annotation.support.ServletResponseMethodArgumentResolver;
-import org.springframework.web.servlet.mvc.method.annotation.support.ServletWebArgumentResolverAdapter;
import org.springframework.web.servlet.mvc.method.annotation.support.ViewMethodReturnValueHandler;
import org.springframework.web.util.WebUtils;
@@ -103,29 +102,30 @@ import org.springframework.web.util.WebUtils;
*
*
{@link InvocableHandlerMethod} is the key contributor that helps with the invocation of handler
* methods of all types resolving their arguments through registered {@link HandlerMethodArgumentResolver}s.
- * {@link ServletInvocableHandlerMethod} on the other hand adds handling of the return value for {@link RequestMapping}
- * methods through registered {@link HandlerMethodReturnValueHandler}s resulting in a {@link ModelAndView}.
+ * {@link ServletInvocableHandlerMethod} on the other hand adds handling of the return value for
+ * {@link RequestMapping} methods through registered {@link HandlerMethodReturnValueHandler}s
+ * resulting in a {@link ModelAndView}.
*
*
{@link ModelFactory} is another contributor that assists with the invocation of all {@link ModelAttribute}
* methods to populate a model while {@link ServletRequestDataBinderFactory} assists with the invocation of
* {@link InitBinder} methods for initializing data binder instances when needed.
*
- *
This class is the central point that assembles all of mentioned contributors and invokes the actual
+ *
This class is the central point that assembles all mentioned contributors and invokes the actual
* {@link RequestMapping} handler method through a {@link ServletInvocableHandlerMethod}.
*
* @author Rossen Stoyanchev
* @since 3.1
- * @see InvocableHandlerMethod
- * @see ServletInvocableHandlerMethod
* @see HandlerMethodArgumentResolver
* @see HandlerMethodReturnValueHandler
+ * @see #setCustomArgumentResolvers(List)
+ * @see #setCustomReturnValueHandlers(List)
*/
public class RequestMappingHandlerAdapter extends AbstractHandlerMethodAdapter implements BeanFactoryAware,
InitializingBean {
- private List extends HandlerMethodArgumentResolver> customArgumentResolvers;
+ private List customArgumentResolvers;
- private List extends HandlerMethodReturnValueHandler> customReturnValueHandlers;
+ private List customReturnValueHandlers;
private List modelAndViewResolvers;
@@ -146,16 +146,16 @@ public class RequestMappingHandlerAdapter extends AbstractHandlerMethodAdapter i
private final Map, SessionAttributesHandler> sessionAttributesHandlerCache =
new ConcurrentHashMap, SessionAttributesHandler>();
- private final Map, Set> modelAttributeMethodCache = new ConcurrentHashMap, Set>();
-
- private final Map, Set> initBinderMethodCache = new ConcurrentHashMap, Set>();
-
- private HandlerMethodReturnValueHandlerComposite returnValueHandlers;
-
private HandlerMethodArgumentResolverComposite argumentResolvers;
private HandlerMethodArgumentResolverComposite initBinderArgumentResolvers;
+ private HandlerMethodReturnValueHandlerComposite returnValueHandlers;
+
+ private final Map, Set> initBinderMethodCache = new ConcurrentHashMap, Set>();
+
+ private final Map, Set> modelAttributeMethodCache = new ConcurrentHashMap, Set>();
+
/**
* Create a {@link RequestMappingHandlerAdapter} instance.
*/
@@ -177,10 +177,8 @@ public class RequestMappingHandlerAdapter extends AbstractHandlerMethodAdapter i
*
Generally custom argument resolvers are invoked first. However this excludes
* default argument resolvers that rely on the presence of annotations (e.g. {@code @RequestParameter},
* {@code @PathVariable}, etc.) Those resolvers can only be customized via {@link #setArgumentResolvers(List)}
- *
An existing {@link WebArgumentResolver} can either adapted with {@link ServletWebArgumentResolverAdapter}
- * or preferably converted to a {@link HandlerMethodArgumentResolver} instead.
*/
- public void setCustomArgumentResolvers(List extends HandlerMethodArgumentResolver> argumentResolvers) {
+ public void setCustomArgumentResolvers(List argumentResolvers) {
this.customArgumentResolvers = argumentResolvers;
}
@@ -190,7 +188,7 @@ public class RequestMappingHandlerAdapter extends AbstractHandlerMethodAdapter i
* {@link #setCustomArgumentResolvers(List)}, which does not override default registrations.
* @param argumentResolvers argument resolvers for {@link RequestMapping} and {@link ModelAttribute} methods
*/
- public void setArgumentResolvers(List extends HandlerMethodArgumentResolver> argumentResolvers) {
+ public void setArgumentResolvers(List argumentResolvers) {
if (argumentResolvers != null) {
this.argumentResolvers = new HandlerMethodArgumentResolverComposite();
this.argumentResolvers.addResolvers(argumentResolvers);
@@ -203,7 +201,7 @@ public class RequestMappingHandlerAdapter extends AbstractHandlerMethodAdapter i
* {@link #setCustomArgumentResolvers(List)}, which does not override default registrations.
* @param argumentResolvers argument resolvers for {@link InitBinder} methods
*/
- public void setInitBinderArgumentResolvers(List extends HandlerMethodArgumentResolver> argumentResolvers) {
+ public void setInitBinderArgumentResolvers(List argumentResolvers) {
if (argumentResolvers != null) {
this.initBinderArgumentResolvers = new HandlerMethodArgumentResolverComposite();
this.initBinderArgumentResolvers.addResolvers(argumentResolvers);
@@ -217,7 +215,7 @@ public class RequestMappingHandlerAdapter extends AbstractHandlerMethodAdapter i
* and others. Those handlers can only be customized via {@link #setReturnValueHandlers(List)}.
* @param returnValueHandlers custom return value handlers for {@link RequestMapping} methods
*/
- public void setCustomReturnValueHandlers(List extends HandlerMethodReturnValueHandler> returnValueHandlers) {
+ public void setCustomReturnValueHandlers(List returnValueHandlers) {
this.customReturnValueHandlers = returnValueHandlers;
}
@@ -227,7 +225,7 @@ public class RequestMappingHandlerAdapter extends AbstractHandlerMethodAdapter i
* {@link #setCustomReturnValueHandlers(List)}, which does not override default registrations.
* @param returnValueHandlers the return value handlers for {@link RequestMapping} methods
*/
- public void setReturnValueHandlers(List extends HandlerMethodReturnValueHandler> returnValueHandlers) {
+ public void setReturnValueHandlers(List returnValueHandlers) {
if (returnValueHandlers != null) {
this.returnValueHandlers = new HandlerMethodReturnValueHandlerComposite();
this.returnValueHandlers.addHandlers(returnValueHandlers);
@@ -236,10 +234,10 @@ public class RequestMappingHandlerAdapter extends AbstractHandlerMethodAdapter i
/**
* Set custom {@link ModelAndViewResolver}s to use to handle the return values of {@link RequestMapping} methods.
- *
Custom {@link ModelAndViewResolver}s are provided for backward compatibility and are invoked at the very,
- * from the {@link DefaultMethodReturnValueHandler}, after all standard {@link HandlerMethodReturnValueHandler}s
- * have been given a chance. This is because {@link ModelAndViewResolver}s do not have a method to indicate
- * if they support a given return type or not. For this reason it is recommended to use
+ *
Custom {@link ModelAndViewResolver}s are provided for backward compatibility and are invoked at the end,
+ * in {@link DefaultMethodReturnValueHandler}, after all standard {@link HandlerMethodReturnValueHandler}s.
+ * This is because {@link ModelAndViewResolver}s do not have a method to indicate if they support a given
+ * return type or not. For this reason it is recommended to use
* {@link HandlerMethodReturnValueHandler} and {@link #setCustomReturnValueHandlers(List)} instead.
*/
public void setModelAndViewResolvers(List modelAndViewResolvers) {
@@ -443,7 +441,8 @@ public class RequestMappingHandlerAdapter extends AbstractHandlerMethodAdapter i
}
/**
- * This method always returns -1 since {@link HandlerMethod} does not implement {@link LastModified}.
+ * {@inheritDoc}
+ *
This implementation always returns -1 since {@link HandlerMethod} does not implement {@link LastModified}.
* Instead an @{@link RequestMapping} method, calculate the lastModified value, and call
* {@link WebRequest#checkNotModified(long)}, and return {@code null} if that returns {@code true}.
* @see WebRequest#checkNotModified(long)
@@ -510,13 +509,11 @@ public class RequestMappingHandlerAdapter extends AbstractHandlerMethodAdapter i
ServletWebRequest webRequest = new ServletWebRequest(request, response);
SessionStatus sessionStatus = new SimpleSessionStatus();
-
+
ModelAndViewContainer mavContainer = new ModelAndViewContainer();
-
modelFactory.initModel(webRequest, mavContainer, requestMethod);
requestMethod.invokeAndHandle(webRequest, mavContainer, sessionStatus);
-
modelFactory.updateModel(webRequest, mavContainer, sessionStatus);
if (!mavContainer.isResolveView()) {
@@ -548,7 +545,6 @@ public class RequestMappingHandlerAdapter extends AbstractHandlerMethodAdapter i
binderMethod.setHandlerMethodArgumentResolvers(this.initBinderArgumentResolvers);
binderMethod.setDataBinderFactory(new DefaultDataBinderFactory(this.webBindingInitializer));
binderMethod.setParameterNameDiscoverer(this.parameterNameDiscoverer);
-
initBinderMethods.add(binderMethod);
}
diff --git a/org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/mvc/method/annotation/support/AbstractMessageConverterMethodArgumentResolver.java b/org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/mvc/method/annotation/support/AbstractMessageConverterMethodArgumentResolver.java
index c1927d83b9..884f01ae4f 100644
--- a/org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/mvc/method/annotation/support/AbstractMessageConverterMethodArgumentResolver.java
+++ b/org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/mvc/method/annotation/support/AbstractMessageConverterMethodArgumentResolver.java
@@ -38,7 +38,8 @@ import org.springframework.web.context.request.NativeWebRequest;
import org.springframework.web.method.support.HandlerMethodArgumentResolver;
/**
- * A base class for resolving method argument values by reading from the body of a request with {@link HttpMessageConverter}s.
+ * A base class for resolving method argument values by reading from the body of a request
+ * with {@link HttpMessageConverter}s.
*
* @author Arjen Poutsma
* @author Rossen Stoyanchev
diff --git a/org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/mvc/method/annotation/support/RequestPartMethodArgumentResolver.java b/org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/mvc/method/annotation/support/RequestPartMethodArgumentResolver.java
index f8db5a9722..eae6068073 100644
--- a/org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/mvc/method/annotation/support/RequestPartMethodArgumentResolver.java
+++ b/org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/mvc/method/annotation/support/RequestPartMethodArgumentResolver.java
@@ -17,17 +17,20 @@
package org.springframework.web.servlet.mvc.method.annotation.support;
import java.lang.annotation.Annotation;
+import java.util.Collection;
import java.util.List;
-import javax.servlet.ServletRequest;
+import javax.servlet.http.HttpServletRequest;
+import org.springframework.core.GenericCollectionTypeResolver;
import org.springframework.core.MethodParameter;
import org.springframework.http.HttpInputMessage;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.util.Assert;
import org.springframework.validation.Errors;
-import org.springframework.validation.Validator;
+import org.springframework.web.bind.ServletRequestBindingException;
import org.springframework.web.bind.WebDataBinder;
+import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestPart;
import org.springframework.web.bind.support.WebDataBinderFactory;
import org.springframework.web.context.request.NativeWebRequest;
@@ -35,21 +38,34 @@ import org.springframework.web.method.support.ModelAndViewContainer;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.multipart.MultipartHttpServletRequest;
import org.springframework.web.multipart.MultipartRequest;
+import org.springframework.web.multipart.MultipartResolver;
import org.springframework.web.multipart.RequestPartServletServerHttpRequest;
-import org.springframework.web.servlet.config.annotation.EnableWebMvc;
import org.springframework.web.servlet.mvc.support.DefaultHandlerExceptionResolver;
import org.springframework.web.util.WebUtils;
/**
- * Resolves method arguments annotated with @{@link RequestPart} expecting the request to be a
- * {@link MultipartHttpServletRequest} and binding the method argument to a specific part of the multipart request.
- * The name of the part is derived either from the {@link RequestPart} annotation or from the name of the method
- * argument as a fallback.
+ * Resolves the following method arguments:
+ *
+ *
Arguments annotated with @{@link RequestPart}.
+ *
Arguments of type {@link MultipartFile} in conjunction with Spring's
+ * {@link MultipartResolver} abstraction.
+ *
Arguments of type {@code javax.servlet.http.Part} in conjunction
+ * with Servlet 3.0 multipart requests.
+ *
*
- *
An @{@link RequestPart} method argument will be validated if annotated with {@code @Valid}. In case of
- * validation failure, a {@link RequestPartNotValidException} is thrown and can be handled automatically through
- * the {@link DefaultHandlerExceptionResolver}. A {@link Validator} can be configured globally in XML configuration
- * with the Spring MVC namespace or in Java-based configuration with @{@link EnableWebMvc}.
+ *
When a parameter is annotated with @{@link 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 non-multipart 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.
+ *
+ *
Automatic validation can be applied to a @{@link RequestPart} method argument
+ * through the use of {@code @Valid}. In case of validation failure, a
+ * {@link RequestPartNotValidException} is thrown and handled automatically through
+ * the {@link DefaultHandlerExceptionResolver}.
*
* @author Rossen Stoyanchev
* @since 3.1
@@ -60,8 +76,27 @@ public class RequestPartMethodArgumentResolver extends AbstractMessageConverterM
super(messageConverters);
}
+ /**
+ * Supports the following:
+ *
+ *
@RequestPart method arguments.
+ *
Arguments of type {@link MultipartFile} even if not annotated.
+ *
Arguments of type {@code javax.servlet.http.Part} even if not annotated.
+ *
+ */
public boolean supportsParameter(MethodParameter parameter) {
- return parameter.hasParameterAnnotation(RequestPart.class);
+ if (parameter.hasParameterAnnotation(RequestPart.class)) {
+ return true;
+ }
+ else if (MultipartFile.class.equals(parameter.getParameterType())) {
+ return true;
+ }
+ else if ("javax.servlet.http.Part".equals(parameter.getParameterType().getName())) {
+ return true;
+ }
+ else {
+ return false;
+ }
}
public Object resolveArgument(MethodParameter parameter,
@@ -69,37 +104,45 @@ public class RequestPartMethodArgumentResolver extends AbstractMessageConverterM
NativeWebRequest request,
WebDataBinderFactory binderFactory) throws Exception {
- ServletRequest servletRequest = request.getNativeRequest(ServletRequest.class);
+ String partName = getPartName(parameter);
+ Object arg;
+
+ HttpServletRequest servletRequest = request.getNativeRequest(HttpServletRequest.class);
MultipartHttpServletRequest multipartRequest =
WebUtils.getNativeRequest(servletRequest, MultipartHttpServletRequest.class);
- if (multipartRequest == null) {
- throw new IllegalStateException(
- "Current request is not of type [" + MultipartRequest.class.getName() + "]: " + request);
+
+ if (MultipartFile.class.equals(parameter.getParameterType())) {
+ assertMultipartRequest(multipartRequest, request);
+ arg = multipartRequest.getFile(partName);
}
-
- String partName = getPartName(parameter);
- if (MultipartFile.class.isAssignableFrom(parameter.getParameterType())) {
- return multipartRequest.getFile(partName);
+ else if (isMultipartFileCollection(parameter)) {
+ assertMultipartRequest(multipartRequest, request);
+ arg = multipartRequest.getFiles(partName);
}
-
- HttpInputMessage inputMessage = new RequestPartServletServerHttpRequest(multipartRequest, partName);
- Object arg = readWithMessageConverters(inputMessage, parameter, parameter.getParameterType());
-
- if (isValidationApplicable(arg, parameter)) {
- WebDataBinder binder = binderFactory.createBinder(request, arg, partName);
- binder.validate();
- Errors errors = binder.getBindingResult();
- if (errors.hasErrors()) {
- throw new RequestPartNotValidException(errors);
+ else if ("javax.servlet.http.Part".equals(parameter.getParameterType().getName())) {
+ arg = servletRequest.getPart(partName);
+ }
+ else {
+ HttpInputMessage inputMessage = new RequestPartServletServerHttpRequest(multipartRequest, partName);
+ arg = readWithMessageConverters(inputMessage, parameter, parameter.getParameterType());
+
+ if (isValidationApplicable(arg, parameter)) {
+ WebDataBinder binder = binderFactory.createBinder(request, arg, partName);
+ binder.validate();
+ Errors errors = binder.getBindingResult();
+ if (errors.hasErrors()) {
+ throw new RequestPartNotValidException(errors);
+ }
}
}
-
+
+ checkMissingRequiredValue(arg, partName, parameter);
return arg;
}
private String getPartName(MethodParameter parameter) {
RequestPart annot = parameter.getParameterAnnotation(RequestPart.class);
- String partName = annot.value();
+ 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()
@@ -108,21 +151,62 @@ public class RequestPartMethodArgumentResolver extends AbstractMessageConverterM
return partName;
}
- /**
- * Whether to validate the given @{@link RequestPart} method argument. The default implementation checks
- * if the parameter is also annotated with {@code @Valid}.
- * @param argumentValue the validation candidate
- * @param parameter the method argument declaring the validation candidate
- * @return {@code true} if validation should be invoked, {@code false} otherwise.
- */
- protected boolean isValidationApplicable(Object argumentValue, MethodParameter parameter) {
- Annotation[] annotations = parameter.getParameterAnnotations();
- for (Annotation annot : annotations) {
- if ("Valid".equals(annot.annotationType().getSimpleName())) {
+ private void assertMultipartRequest(MultipartHttpServletRequest multipartRequest, NativeWebRequest request) {
+ if (multipartRequest == null) {
+ throw new IllegalStateException("Current request is not of type [" + MultipartRequest.class.getName()
+ + "]: " + request + ". Do you have a MultipartResolver configured?");
+ }
+ }
+
+ private boolean isMultipartFileCollection(MethodParameter parameter) {
+ Class> paramType = parameter.getParameterType();
+ if (Collection.class.equals(paramType) || List.class.isAssignableFrom(paramType)){
+ Class> valueType = GenericCollectionTypeResolver.getCollectionParameterType(parameter);
+ if (valueType != null && valueType.equals(MultipartFile.class)) {
return true;
}
}
return false;
}
+
+ /**
+ * Raises a {@link ServletRequestBindingException} if the method parameter is required
+ * and the resolved argument value is null.
+ */
+ protected void checkMissingRequiredValue(Object argumentValue, String partName, MethodParameter parameter)
+ throws ServletRequestBindingException {
+ if (argumentValue == null) {
+ RequestPart annot = parameter.getParameterAnnotation(RequestPart.class);
+ boolean isRequired = (annot != null) ? annot.required() : true;
+ if (isRequired) {
+ String paramType = parameter.getParameterType().getName();
+ throw new ServletRequestBindingException(
+ "Missing request part '" + partName + "' for method parameter type [" + paramType + "]");
+ }
+ }
+ }
+
+ /**
+ * Whether to validate the given @{@link RequestPart} method argument.
+ * The default implementation return {@code true} if the argument value is not {@code null}
+ * and the method parameter is annotated with {@code @Valid}.
+ * @param argumentValue the validation candidate
+ * @param parameter the method argument declaring the validation candidate
+ * @return {@code true} if validation should be invoked, {@code false} otherwise.
+ */
+ protected boolean isValidationApplicable(Object argumentValue, MethodParameter parameter) {
+ if (argumentValue == null) {
+ return false;
+ }
+ else {
+ Annotation[] annotations = parameter.getParameterAnnotations();
+ for (Annotation annot : annotations) {
+ if ("Valid".equals(annot.annotationType().getSimpleName())) {
+ return true;
+ }
+ }
+ return false;
+ }
+ }
}
diff --git a/org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/mvc/method/annotation/support/RequestResponseBodyMethodProcessor.java b/org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/mvc/method/annotation/support/RequestResponseBodyMethodProcessor.java
index 092f2c4b92..20fbdc73d7 100644
--- a/org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/mvc/method/annotation/support/RequestResponseBodyMethodProcessor.java
+++ b/org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/mvc/method/annotation/support/RequestResponseBodyMethodProcessor.java
@@ -24,7 +24,6 @@ import org.springframework.core.Conventions;
import org.springframework.core.MethodParameter;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.validation.Errors;
-import org.springframework.validation.Validator;
import org.springframework.web.HttpMediaTypeNotAcceptableException;
import org.springframework.web.bind.WebDataBinder;
import org.springframework.web.bind.annotation.RequestBody;
@@ -32,17 +31,15 @@ import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.support.WebDataBinderFactory;
import org.springframework.web.context.request.NativeWebRequest;
import org.springframework.web.method.support.ModelAndViewContainer;
-import org.springframework.web.servlet.config.annotation.EnableWebMvc;
import org.springframework.web.servlet.mvc.support.DefaultHandlerExceptionResolver;
/**
* Resolves method arguments annotated with @{@link RequestBody} and handles return values from methods
* annotated with {@link ResponseBody}.
*
- *
An @{@link RequestBody} method argument will be validated if annotated with {@code @Valid}. In case of
- * validation failure, a {@link RequestBodyNotValidException} is thrown and can be handled automatically through
- * the {@link DefaultHandlerExceptionResolver}. A {@link Validator} can be configured globally in XML configuration
- * with the Spring MVC namespace or in Java-based configuration with @{@link EnableWebMvc}.
+ *
An @{@link RequestBody} method argument will be validated if annotated with {@code @Valid}.
+ * In case of validation failure, a {@link RequestBodyNotValidException} is thrown and handled
+ * automatically in {@link DefaultHandlerExceptionResolver}.
*
* @author Arjen Poutsma
* @author Rossen Stoyanchev
diff --git a/org.springframework.web.servlet/src/test/java/org/springframework/mock/web/MockHttpServletRequest.java b/org.springframework.web.servlet/src/test/java/org/springframework/mock/web/MockHttpServletRequest.java
index 26f7171b58..fd599c2d23 100644
--- a/org.springframework.web.servlet/src/test/java/org/springframework/mock/web/MockHttpServletRequest.java
+++ b/org.springframework.web.servlet/src/test/java/org/springframework/mock/web/MockHttpServletRequest.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2002-2009 the original author or authors.
+ * Copyright 2002-2011 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,6 +18,7 @@ package org.springframework.mock.web;
import java.io.BufferedReader;
import java.io.ByteArrayInputStream;
+import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.Reader;
@@ -27,6 +28,7 @@ import java.util.Collection;
import java.util.Collections;
import java.util.Date;
import java.util.Enumeration;
+import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedHashMap;
import java.util.LinkedList;
@@ -34,19 +36,28 @@ import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Set;
+
+import javax.servlet.AsyncContext;
+import javax.servlet.DispatcherType;
import javax.servlet.RequestDispatcher;
import javax.servlet.ServletContext;
+import javax.servlet.ServletException;
import javax.servlet.ServletInputStream;
+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 javax.servlet.http.Part;
import org.springframework.util.Assert;
import org.springframework.util.LinkedCaseInsensitiveMap;
/**
* Mock implementation of the {@link javax.servlet.http.HttpServletRequest}
- * interface. Supports the Servlet 2.5 API level.
+ * interface. Supports the Servlet 2.5 API level; throws
+ * {@link UnsupportedOperationException} for all methods introduced in Servlet 3.0.
*
*
Used for testing the web framework; also useful for testing
* application controllers.
@@ -55,6 +66,7 @@ import org.springframework.util.LinkedCaseInsensitiveMap;
* @author Rod Johnson
* @author Rick Evans
* @author Mark Fisher
+ * @author Chris Beams
* @since 1.0.2
*/
public class MockHttpServletRequest implements HttpServletRequest {
@@ -134,6 +146,7 @@ public class MockHttpServletRequest implements HttpServletRequest {
private int localPort = DEFAULT_SERVER_PORT;
+ private Map parts = new HashMap();
//---------------------------------------------------------------------
// HttpServletRequest properties
@@ -847,4 +860,57 @@ public class MockHttpServletRequest implements HttpServletRequest {
return isRequestedSessionIdFromURL();
}
+
+ //---------------------------------------------------------------------
+ // Methods introduced in Servlet 3.0
+ //---------------------------------------------------------------------
+
+ public AsyncContext getAsyncContext() {
+ throw new UnsupportedOperationException();
+ }
+
+ public DispatcherType getDispatcherType() {
+ throw new UnsupportedOperationException();
+ }
+
+ public boolean isAsyncSupported() {
+ throw new UnsupportedOperationException();
+ }
+
+ public AsyncContext startAsync() {
+ throw new UnsupportedOperationException();
+ }
+
+ public AsyncContext startAsync(ServletRequest arg0, ServletResponse arg1) {
+ throw new UnsupportedOperationException();
+ }
+
+ public boolean isAsyncStarted() {
+ throw new UnsupportedOperationException();
+ }
+
+ public boolean authenticate(HttpServletResponse arg0) throws IOException, ServletException {
+ throw new UnsupportedOperationException();
+ }
+
+ public void addPart(Part part) {
+ parts.put(part.getName(), part);
+ }
+
+ public Part getPart(String key) throws IOException, IllegalStateException, ServletException {
+ return parts.get(key);
+ }
+
+ public Collection getParts() throws IOException, IllegalStateException, ServletException {
+ return parts.values();
+ }
+
+ public void login(String arg0, String arg1) throws ServletException {
+ throw new UnsupportedOperationException();
+ }
+
+ public void logout() throws ServletException {
+ throw new UnsupportedOperationException();
+ }
+
}
diff --git a/org.springframework.web.servlet/src/test/java/org/springframework/mock/web/MockHttpServletResponse.java b/org.springframework.web.servlet/src/test/java/org/springframework/mock/web/MockHttpServletResponse.java
index 46eb174615..9f55159e7a 100644
--- a/org.springframework.web.servlet/src/test/java/org/springframework/mock/web/MockHttpServletResponse.java
+++ b/org.springframework.web.servlet/src/test/java/org/springframework/mock/web/MockHttpServletResponse.java
@@ -29,6 +29,7 @@ import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Set;
+
import javax.servlet.ServletOutputStream;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletResponse;
@@ -292,9 +293,9 @@ public class MockHttpServletResponse implements HttpServletResponse {
* @param name the name of the header
* @return the associated header value, or null if none
*/
- public Object getHeader(String name) {
+ public String getHeader(String name) {
HeaderValueHolder header = HeaderValueHolder.getByName(this.headers, name);
- return (header != null ? header.getValue() : null);
+ return (header != null ? header.getValue().toString() : null);
}
/**
@@ -302,9 +303,9 @@ public class MockHttpServletResponse implements HttpServletResponse {
* @param name the name of the header
* @return the associated header values, or an empty List if none
*/
- public List