diff --git a/org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/config/MvcAnnotationDriven.java b/org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/config/MvcAnnotationDriven.java
index a3c24f79c8b..b28afea5556 100644
--- a/org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/config/MvcAnnotationDriven.java
+++ b/org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/config/MvcAnnotationDriven.java
@@ -30,6 +30,8 @@ import org.springframework.validation.MessageCodesResolver;
import org.springframework.validation.Validator;
import org.springframework.validation.beanvalidation.LocalValidatorFactoryBean;
import org.springframework.web.bind.support.WebArgumentResolver;
+import org.springframework.web.method.support.HandlerMethodArgumentResolver;
+import org.springframework.web.servlet.mvc.method.annotation.support.ServletWebArgumentResolverAdapter;
/**
* Specifies the Spring MVC "annotation-driven" container feature. The
@@ -167,9 +169,16 @@ public final class MvcAnnotationDriven extends AbstractFeatureSpecification {
return this.shouldRegisterDefaultMessageConverters;
}
+ public MvcAnnotationDriven argumentResolvers(HandlerMethodArgumentResolver... resolvers) {
+ for (HandlerMethodArgumentResolver resolver : resolvers) {
+ this.argumentResolvers.add(resolver);
+ }
+ return this;
+ }
+
public MvcAnnotationDriven argumentResolvers(WebArgumentResolver... resolvers) {
for (WebArgumentResolver resolver : resolvers) {
- this.argumentResolvers.add(resolver);
+ this.argumentResolvers.add(new ServletWebArgumentResolverAdapter(resolver));
}
return this;
}
diff --git a/org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/mvc/method/annotation/RequestMappingHandlerMethodAdapter.java b/org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/mvc/method/annotation/RequestMappingHandlerMethodAdapter.java
index 877f29f59b1..88a77a95937 100644
--- a/org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/mvc/method/annotation/RequestMappingHandlerMethodAdapter.java
+++ b/org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/mvc/method/annotation/RequestMappingHandlerMethodAdapter.java
@@ -93,23 +93,23 @@ import org.springframework.web.servlet.mvc.method.annotation.support.ViewMethodR
import org.springframework.web.util.WebUtils;
/**
- * A {@link AbstractHandlerMethodAdapter} variant with support for invoking {@link RequestMapping} handler methods.
+ * An {@link AbstractHandlerMethodAdapter} variant with support for {@link RequestMapping} handler methods.
*
- *
Invoking a {@link RequestMapping} method typically involves the invocation of other handler methods such as
- * {@link ModelAttribute} methods for contributing attributes to the model and {@link InitBinder} methods for
- * initializing {@link WebDataBinder} instances for data binding and type conversion purposes.
+ *
Processing a {@link RequestMapping} method typically involves the invocation of {@link ModelAttribute}
+ * methods for contributing attributes to the model and {@link InitBinder} methods for initializing
+ * {@link WebDataBinder} instances for data binding and type conversion purposes.
*
- *
{@link InvocableHandlerMethod} is the key contributing class that helps with the invocation of any handler
- * method after resolving its arguments through a set of {@link HandlerMethodArgumentResolver}s.
- * {@link ServletInvocableHandlerMethod} on the other hand, handles the return value through a set of
- * {@link HandlerMethodReturnValueHandler}s resulting in a {@link ModelAndView} when view resolution applies.
+ *
{@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}.
*
- *
Specifically assisting with the invocation of {@link ModelAttribute} methods is the {@link ModelFactory} while
- * the invocation of {@link InitBinder} methods is done with the help of the {@link InitBinderMethodDataBinderFactory},
- * which is passed on to {@link HandlerMethodArgumentResolver}s where data binder instances are needed.
+ *
{@link ModelFactory} is another contributor that assists with the invocation of all {@link ModelAttribute}
+ * methods to populate a model while {@link InitBinderMethodDataBinderFactory} 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 the above mentioned contributors and drives them while
- * also invoking the actual {@link RequestMapping} handler method through a {@link ServletInvocableHandlerMethod}.
+ *
This class is the central point that assembles all of mentioned contributors and invokes the actual
+ * {@link RequestMapping} handler method through a {@link ServletInvocableHandlerMethod}.
*
* @author Rossen Stoyanchev
* @since 3.1
@@ -121,11 +121,15 @@ import org.springframework.web.util.WebUtils;
public class RequestMappingHandlerMethodAdapter extends AbstractHandlerMethodAdapter implements BeanFactoryAware,
InitializingBean {
- private WebArgumentResolver[] customArgumentResolvers;
+ private final List customArgumentResolvers =
+ new ArrayList();
- private ModelAndViewResolver[] customModelAndViewResolvers;
+ private final List customReturnValueHandlers =
+ new ArrayList();
+
+ private final List modelAndViewResolvers = new ArrayList();
- private HttpMessageConverter>[] messageConverters;
+ private List> messageConverters;
private WebBindingInitializer webBindingInitializer;
@@ -160,45 +164,118 @@ public class RequestMappingHandlerMethodAdapter extends AbstractHandlerMethodAda
StringHttpMessageConverter stringHttpMessageConverter = new StringHttpMessageConverter();
stringHttpMessageConverter.setWriteAcceptCharset(false); // See SPR-7316
- this.messageConverters = new HttpMessageConverter[] { new ByteArrayHttpMessageConverter(),
- stringHttpMessageConverter, new SourceHttpMessageConverter(),
- new XmlAwareFormHttpMessageConverter() };
+ messageConverters = new ArrayList>();
+ messageConverters.add(new ByteArrayHttpMessageConverter());
+ messageConverters.add(stringHttpMessageConverter);
+ messageConverters.add(new SourceHttpMessageConverter());
+ messageConverters.add(new XmlAwareFormHttpMessageConverter());
}
/**
- * 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.
- *
Note: this is provided for backward compatibility. The preferred way to do this is to
- * implement a {@link HandlerMethodArgumentResolver}.
+ * Set one or more custom argument resolvers to use with {@link RequestMapping}, {@link ModelAttribute}, and
+ * {@link InitBinder} methods. Custom argument resolvers are given a chance to resolve argument values
+ * ahead of the standard argument resolvers registered by default.
+ *
Argument resolvers of type {@link HandlerMethodArgumentResolver} and {@link WebArgumentResolver} are
+ * accepted with instances of the latter adapted via {@link ServletWebArgumentResolverAdapter}. For new
+ * implementations {@link HandlerMethodArgumentResolver} should be preferred over {@link WebArgumentResolver}.
*/
- public void setCustomArgumentResolvers(WebArgumentResolver[] argumentResolvers) {
- this.customArgumentResolvers = argumentResolvers;
+ public void setCustomArgumentResolvers(List> argumentResolvers) {
+ if (argumentResolvers == null) {
+ return;
+ }
+ List adaptedResolvers = new ArrayList();
+ for (Object resolver : argumentResolvers) {
+ if (resolver instanceof WebArgumentResolver) {
+ adaptedResolvers.add(new ServletWebArgumentResolverAdapter((WebArgumentResolver) resolver));
+ }
+ else if (resolver instanceof HandlerMethodArgumentResolver) {
+ adaptedResolvers.add((HandlerMethodArgumentResolver) resolver);
+ }
+ else {
+ throw new IllegalArgumentException(
+ "An argument resolver must be a HandlerMethodArgumentResolver or a WebArgumentResolver");
+ }
+ }
+ this.customArgumentResolvers.addAll(adaptedResolvers);
+ }
+
+ /**
+ * Set the argument resolvers to use with {@link RequestMapping} and {@link ModelAttribute} methods.
+ * This is an optional property providing full control over all argument resolvers in contrast to
+ * {@link #setCustomArgumentResolvers(List)}, which does not override default registrations.
+ * @param argumentResolvers argument resolvers for {@link RequestMapping} and {@link ModelAttribute} methods
+ */
+ public void setArgumentResolvers(List argumentResolvers) {
+ if (argumentResolvers != null) {
+ this.argumentResolvers = new HandlerMethodArgumentResolverComposite();
+ registerArgumentResolvers(argumentResolvers);
+ }
+ }
+
+ /**
+ * Set the argument resolvers to use with {@link InitBinder} methods. This is an optional property
+ * providing full control over all argument resolvers for {@link InitBinder} methods in contrast to
+ * {@link #setCustomArgumentResolvers(List)}, which does not override default registrations.
+ * @param argumentResolvers argument resolvers for {@link InitBinder} methods
+ */
+ public void setInitBinderArgumentResolvers(List argumentResolvers) {
+ if (argumentResolvers != null) {
+ this.initBinderArgumentResolvers = new HandlerMethodArgumentResolverComposite();
+ registerInitBinderArgumentResolvers(argumentResolvers);
+ }
}
/**
- * 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.
- *
Note: this is provided for backward compatibility. The preferred way to do this is to
- * implement a {@link HandlerMethodReturnValueHandler}.
+ * Set custom return value handlers to use to handle the return values of {@link RequestMapping} methods.
+ * Custom return value handlers are given a chance to handle a return value before the standard
+ * return value handlers registered by default.
+ * @param returnValueHandlers custom return value handlers for {@link RequestMapping} methods
*/
- public void setCustomModelAndViewResolvers(ModelAndViewResolver[] customModelAndViewResolvers) {
- this.customModelAndViewResolvers = customModelAndViewResolvers;
+ public void setCustomReturnValueHandlers(List returnValueHandlers) {
+ if (returnValueHandlers != null) {
+ this.customReturnValueHandlers.addAll(returnValueHandlers);
+ }
+ }
+
+ /**
+ * Set the {@link HandlerMethodReturnValueHandler}s to use to use with {@link RequestMapping} methods.
+ * This is an optional property providing full control over all return value handlers in contrast to
+ * {@link #setCustomReturnValueHandlers(List)}, which does not override default registrations.
+ * @param returnValueHandlers the return value handlers for {@link RequestMapping} methods
+ */
+ public void setReturnValueHandlers(List returnValueHandlers) {
+ if (returnValueHandlers != null) {
+ this.returnValueHandlers = new HandlerMethodReturnValueHandlerComposite();
+ registerReturnValueHandlers(returnValueHandlers);
+ }
+ }
+
+ /**
+ * 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
+ * {@link HandlerMethodReturnValueHandler} and {@link #setCustomReturnValueHandlers(List)} instead.
+ */
+ public void setModelAndViewResolvers(List modelAndViewResolvers) {
+ if (modelAndViewResolvers != null) {
+ this.modelAndViewResolvers.addAll(modelAndViewResolvers);
+ }
}
/**
* 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) {
+ public void setMessageConverters(List> messageConverters) {
this.messageConverters = messageConverters;
}
/**
* Return the message body converters that this adapter has been configured with.
*/
- public HttpMessageConverter>[] getMessageConverters() {
+ public List> getMessageConverters() {
return messageConverters;
}
@@ -263,42 +340,6 @@ public class RequestMappingHandlerMethodAdapter extends AbstractHandlerMethodAda
this.parameterNameDiscoverer = parameterNameDiscoverer;
}
- /**
- * Set the {@link HandlerMethodArgumentResolver}s to use to resolve argument values for {@link RequestMapping}
- * and {@link ModelAttribute} methods. This is an optional property.
- * @param argumentResolvers the argument resolvers to use
- */
- public void setHandlerMethodArgumentResolvers(HandlerMethodArgumentResolver[] argumentResolvers) {
- this.argumentResolvers = new HandlerMethodArgumentResolverComposite();
- for (HandlerMethodArgumentResolver resolver : argumentResolvers) {
- this.argumentResolvers.registerArgumentResolver(resolver);
- }
- }
-
- /**
- * Set the {@link HandlerMethodReturnValueHandler}s to use to handle the return values of
- * {@link RequestMapping} methods. This is an optional property.
- * @param returnValueHandlers the return value handlers to use
- */
- public void setHandlerMethodReturnValueHandlers(HandlerMethodReturnValueHandler[] returnValueHandlers) {
- this.returnValueHandlers = new HandlerMethodReturnValueHandlerComposite();
- for (HandlerMethodReturnValueHandler handler : returnValueHandlers) {
- this.returnValueHandlers.registerReturnValueHandler(handler);
- }
- }
-
- /**
- * Set the {@link HandlerMethodArgumentResolver}s to use to resolve argument values for {@link InitBinder}
- * methods. This is an optional property.
- * @param argumentResolvers the argument resolvers to use
- */
- public void setInitBinderMethodArgumentResolvers(HandlerMethodArgumentResolver[] argumentResolvers) {
- this.initBinderArgumentResolvers = new HandlerMethodArgumentResolverComposite();
- for (HandlerMethodArgumentResolver resolver : argumentResolvers) {
- this.initBinderArgumentResolvers.registerArgumentResolver(resolver);
- }
- }
-
public void setBeanFactory(BeanFactory beanFactory) {
if (beanFactory instanceof ConfigurableBeanFactory) {
this.beanFactory = (ConfigurableBeanFactory) beanFactory;
@@ -306,90 +347,110 @@ public class RequestMappingHandlerMethodAdapter extends AbstractHandlerMethodAda
}
public void afterPropertiesSet() throws Exception {
- initHandlerMethodArgumentResolvers();
- initHandlerMethodReturnValueHandlers();
- initBinderMethodArgumentResolvers();
+ if (argumentResolvers == null) {
+ argumentResolvers = new HandlerMethodArgumentResolverComposite();
+ registerArgumentResolvers(customArgumentResolvers);
+ registerArgumentResolvers(getDefaultArgumentResolvers(messageConverters, beanFactory));
+ }
+ if (returnValueHandlers == null) {
+ returnValueHandlers = new HandlerMethodReturnValueHandlerComposite();
+ registerReturnValueHandlers(customReturnValueHandlers);
+ registerReturnValueHandlers(getDefaultReturnValueHandlers(messageConverters, modelAndViewResolvers));
+ }
+ if (initBinderArgumentResolvers == null) {
+ initBinderArgumentResolvers = new HandlerMethodArgumentResolverComposite();
+ registerInitBinderArgumentResolvers(customArgumentResolvers);
+ registerInitBinderArgumentResolvers(getDefaultInitBinderArgumentResolvers(beanFactory));
+ }
}
- private void initHandlerMethodArgumentResolvers() {
- if (argumentResolvers != null) {
- return;
+ private void registerArgumentResolvers(List argumentResolvers) {
+ for (HandlerMethodArgumentResolver resolver : argumentResolvers) {
+ this.argumentResolvers.registerArgumentResolver(resolver);
}
- argumentResolvers = new HandlerMethodArgumentResolverComposite();
-
- // Annotation-based resolvers
- argumentResolvers.registerArgumentResolver(new RequestParamMethodArgumentResolver(beanFactory, false));
- argumentResolvers.registerArgumentResolver(new RequestParamMapMethodArgumentResolver());
- argumentResolvers.registerArgumentResolver(new PathVariableMethodArgumentResolver(beanFactory));
- argumentResolvers.registerArgumentResolver(new ServletModelAttributeMethodProcessor(false));
- argumentResolvers.registerArgumentResolver(new RequestResponseBodyMethodProcessor(messageConverters));
- argumentResolvers.registerArgumentResolver(new RequestHeaderMethodArgumentResolver(beanFactory));
- argumentResolvers.registerArgumentResolver(new RequestHeaderMapMethodArgumentResolver());
- argumentResolvers.registerArgumentResolver(new ServletCookieValueMethodArgumentResolver(beanFactory));
- argumentResolvers.registerArgumentResolver(new ExpressionValueMethodArgumentResolver(beanFactory));
-
- if (customArgumentResolvers != null) {
- for (WebArgumentResolver customResolver : customArgumentResolvers) {
- argumentResolvers.registerArgumentResolver(new ServletWebArgumentResolverAdapter(customResolver));
- }
- }
-
- // Type-based resolvers
- argumentResolvers.registerArgumentResolver(new ServletRequestMethodArgumentResolver());
- argumentResolvers.registerArgumentResolver(new ServletResponseMethodArgumentResolver());
- argumentResolvers.registerArgumentResolver(new HttpEntityMethodProcessor(messageConverters));
- argumentResolvers.registerArgumentResolver(new ModelMethodProcessor());
- argumentResolvers.registerArgumentResolver(new ErrorsMethodArgumentResolver());
-
- // Default-mode resolution
- argumentResolvers.registerArgumentResolver(new RequestParamMethodArgumentResolver(beanFactory, true));
- argumentResolvers.registerArgumentResolver(new ServletModelAttributeMethodProcessor(true));
- }
-
- private void initBinderMethodArgumentResolvers() {
- if (initBinderArgumentResolvers != null) {
- return;
- }
- initBinderArgumentResolvers = new HandlerMethodArgumentResolverComposite();
-
- // Annotation-based resolvers
- initBinderArgumentResolvers.registerArgumentResolver(new RequestParamMethodArgumentResolver(beanFactory, false));
- initBinderArgumentResolvers.registerArgumentResolver(new RequestParamMapMethodArgumentResolver());
- initBinderArgumentResolvers.registerArgumentResolver(new PathVariableMethodArgumentResolver(beanFactory));
- initBinderArgumentResolvers.registerArgumentResolver(new ExpressionValueMethodArgumentResolver(beanFactory));
-
- if (customArgumentResolvers != null) {
- for (WebArgumentResolver customResolver : customArgumentResolvers) {
- initBinderArgumentResolvers.registerArgumentResolver(new ServletWebArgumentResolverAdapter(customResolver));
- }
- }
-
- // Type-based resolvers
- initBinderArgumentResolvers.registerArgumentResolver(new ServletRequestMethodArgumentResolver());
- initBinderArgumentResolvers.registerArgumentResolver(new ServletResponseMethodArgumentResolver());
-
- // Default-mode resolution
- initBinderArgumentResolvers.registerArgumentResolver(new RequestParamMethodArgumentResolver(beanFactory, true));
}
- private void initHandlerMethodReturnValueHandlers() {
- if (returnValueHandlers != null) {
- return;
+ private void registerInitBinderArgumentResolvers(List argumentResolvers) {
+ for (HandlerMethodArgumentResolver resolver : argumentResolvers) {
+ this.initBinderArgumentResolvers.registerArgumentResolver(resolver);
}
- returnValueHandlers = new HandlerMethodReturnValueHandlerComposite();
+ }
+
+ private void registerReturnValueHandlers(List returnValueHandlers) {
+ for (HandlerMethodReturnValueHandler handler : returnValueHandlers) {
+ this.returnValueHandlers.registerReturnValueHandler(handler);
+ }
+ }
+
+ public static List getDefaultArgumentResolvers(
+ List> messageConverters, ConfigurableBeanFactory beanFactory) {
+
+ List resolvers = new ArrayList();
+
+ resolvers.add(new RequestParamMethodArgumentResolver(beanFactory, false));
+ resolvers.add(new RequestParamMapMethodArgumentResolver());
+ resolvers.add(new PathVariableMethodArgumentResolver(beanFactory));
+ resolvers.add(new ServletModelAttributeMethodProcessor(false));
+ resolvers.add(new RequestResponseBodyMethodProcessor(messageConverters));
+ resolvers.add(new RequestHeaderMethodArgumentResolver(beanFactory));
+ resolvers.add(new RequestHeaderMapMethodArgumentResolver());
+ resolvers.add(new ServletCookieValueMethodArgumentResolver(beanFactory));
+ resolvers.add(new ExpressionValueMethodArgumentResolver(beanFactory));
+
+ // Type-based resolvers
+ resolvers.add(new ServletRequestMethodArgumentResolver());
+ resolvers.add(new ServletResponseMethodArgumentResolver());
+ resolvers.add(new HttpEntityMethodProcessor(messageConverters));
+ resolvers.add(new ModelMethodProcessor());
+ resolvers.add(new ErrorsMethodArgumentResolver());
+
+ // Default-mode resolution
+ resolvers.add(new RequestParamMethodArgumentResolver(beanFactory, true));
+ resolvers.add(new ServletModelAttributeMethodProcessor(true));
+
+ return resolvers;
+ }
+
+ public static List getDefaultInitBinderArgumentResolvers(
+ ConfigurableBeanFactory beanFactory) {
+
+ List resolvers = new ArrayList();
+
+ // Annotation-based resolvers
+ resolvers.add(new RequestParamMethodArgumentResolver(beanFactory, false));
+ resolvers.add(new RequestParamMapMethodArgumentResolver());
+ resolvers.add(new PathVariableMethodArgumentResolver(beanFactory));
+ resolvers.add(new ExpressionValueMethodArgumentResolver(beanFactory));
+
+ // Type-based resolvers
+ resolvers.add(new ServletRequestMethodArgumentResolver());
+ resolvers.add(new ServletResponseMethodArgumentResolver());
+
+ // Default-mode resolution
+ resolvers.add(new RequestParamMethodArgumentResolver(beanFactory, true));
+
+ return resolvers;
+ }
+
+ public static List getDefaultReturnValueHandlers(
+ List> messageConverters, List modelAndViewResolvers) {
+
+ List handlers = new ArrayList();
// Annotation-based handlers
- returnValueHandlers.registerReturnValueHandler(new RequestResponseBodyMethodProcessor(messageConverters));
- returnValueHandlers.registerReturnValueHandler(new ModelAttributeMethodProcessor(false));
+ handlers.add(new RequestResponseBodyMethodProcessor(messageConverters));
+ handlers.add(new ModelAttributeMethodProcessor(false));
// Type-based handlers
- returnValueHandlers.registerReturnValueHandler(new ModelAndViewMethodReturnValueHandler());
- returnValueHandlers.registerReturnValueHandler(new ModelMethodProcessor());
- returnValueHandlers.registerReturnValueHandler(new ViewMethodReturnValueHandler());
- returnValueHandlers.registerReturnValueHandler(new HttpEntityMethodProcessor(messageConverters));
+ handlers.add(new ModelAndViewMethodReturnValueHandler());
+ handlers.add(new ModelMethodProcessor());
+ handlers.add(new ViewMethodReturnValueHandler());
+ handlers.add(new HttpEntityMethodProcessor(messageConverters));
// Default handler
- returnValueHandlers.registerReturnValueHandler(new DefaultMethodReturnValueHandler(customModelAndViewResolvers));
+ handlers.add(new DefaultMethodReturnValueHandler(modelAndViewResolvers));
+
+ return handlers;
}
@Override
diff --git a/org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/mvc/method/annotation/RequestMappingHandlerMethodExceptionResolver.java b/org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/mvc/method/annotation/RequestMappingHandlerMethodExceptionResolver.java
index c89f106a48a..31d5994212f 100644
--- a/org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/mvc/method/annotation/RequestMappingHandlerMethodExceptionResolver.java
+++ b/org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/mvc/method/annotation/RequestMappingHandlerMethodExceptionResolver.java
@@ -17,6 +17,8 @@
package org.springframework.web.servlet.mvc.method.annotation;
import java.lang.reflect.Method;
+import java.util.ArrayList;
+import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
@@ -80,9 +82,13 @@ import org.springframework.web.servlet.mvc.method.annotation.support.ViewMethodR
public class RequestMappingHandlerMethodExceptionResolver extends AbstractHandlerMethodExceptionResolver implements
InitializingBean {
- private WebArgumentResolver[] customArgumentResolvers;
+ private final List customArgumentResolvers =
+ new ArrayList();
- private HttpMessageConverter>[] messageConverters;
+ private final List customReturnValueHandlers =
+ new ArrayList();
+
+ private List> messageConverters;
private final Map, ExceptionMethodMapping> exceptionMethodMappingCache =
new ConcurrentHashMap, ExceptionMethodMapping>();
@@ -99,95 +105,139 @@ public class RequestMappingHandlerMethodExceptionResolver extends AbstractHandle
StringHttpMessageConverter stringHttpMessageConverter = new StringHttpMessageConverter();
stringHttpMessageConverter.setWriteAcceptCharset(false); // See SPR-7316
- this.messageConverters = new HttpMessageConverter[] { new ByteArrayHttpMessageConverter(),
- stringHttpMessageConverter, new SourceHttpMessageConverter(),
- new XmlAwareFormHttpMessageConverter() };
+ messageConverters = new ArrayList>();
+ messageConverters.add(new ByteArrayHttpMessageConverter());
+ messageConverters.add(stringHttpMessageConverter);
+ messageConverters.add(new SourceHttpMessageConverter());
+ messageConverters.add(new XmlAwareFormHttpMessageConverter());
}
/**
- * Set one or more custom ArgumentResolvers to use for special method parameter types.
- *
Any such custom ArgumentResolver will kick in first, having a chance to resolve
- * an argument value before the standard argument handling kicks in.
- *
Note: this is provided for backward compatibility. The preferred way to do this is to
- * implement a {@link HandlerMethodArgumentResolver}.
+ * Set one or more custom argument resolvers to use with {@link ExceptionHandler} methods. Custom argument resolvers
+ * are given a chance to resolve argument values ahead of the standard argument resolvers registered by default.
+ *
Argument resolvers of type {@link HandlerMethodArgumentResolver} and {@link WebArgumentResolver} are
+ * accepted with instances of the latter adapted via {@link ServletWebArgumentResolverAdapter}. For new
+ * implementations {@link HandlerMethodArgumentResolver} should be preferred over {@link WebArgumentResolver}.
*/
- public void setCustomArgumentResolvers(WebArgumentResolver[] argumentResolvers) {
- this.customArgumentResolvers = argumentResolvers;
+ public void setCustomArgumentResolvers(List> argumentResolvers) {
+ if (argumentResolvers == null) {
+ return;
+ }
+ List adaptedResolvers = new ArrayList();
+ for (Object resolver : argumentResolvers) {
+ if (resolver instanceof WebArgumentResolver) {
+ adaptedResolvers.add(new ServletWebArgumentResolverAdapter((WebArgumentResolver) resolver));
+ }
+ else if (resolver instanceof HandlerMethodArgumentResolver) {
+ adaptedResolvers.add((HandlerMethodArgumentResolver) resolver);
+ }
+ else {
+ throw new IllegalArgumentException(
+ "An argument resolver must be a HandlerMethodArgumentResolver or a WebArgumentResolver");
+ }
+ }
+ this.customArgumentResolvers.addAll(adaptedResolvers);
+ }
+
+ /**
+ * Set the argument resolvers to use with {@link ExceptionHandler} methods.
+ * This is an optional property providing full control over all argument resolvers in contrast to
+ * {@link #setCustomArgumentResolvers(List)}, which does not override default registrations.
+ * @param argumentResolvers argument resolvers for {@link ExceptionHandler} methods
+ */
+ public void setArgumentResolvers(List argumentResolvers) {
+ if (argumentResolvers != null) {
+ this.argumentResolvers = new HandlerMethodArgumentResolverComposite();
+ registerArgumentResolvers(argumentResolvers);
+ }
}
+ /**
+ * Set custom return value handlers to use to handle the return values of {@link ExceptionHandler} methods.
+ * Custom return value handlers are given a chance to handle a return value before the standard
+ * return value handlers registered by default.
+ * @param returnValueHandlers custom return value handlers for {@link ExceptionHandler} methods
+ */
+ public void setCustomReturnValueHandlers(List returnValueHandlers) {
+ if (returnValueHandlers != null) {
+ this.customReturnValueHandlers.addAll(returnValueHandlers);
+ }
+ }
+
+ /**
+ * Set the {@link HandlerMethodReturnValueHandler}s to use to use with {@link ExceptionHandler} methods.
+ * This is an optional property providing full control over all return value handlers in contrast to
+ * {@link #setCustomReturnValueHandlers(List)}, which does not override default registrations.
+ * @param returnValueHandlers the return value handlers for {@link ExceptionHandler} methods
+ */
+ public void setReturnValueHandlers(List returnValueHandlers) {
+ if (returnValueHandlers != null) {
+ this.returnValueHandlers = new HandlerMethodReturnValueHandlerComposite();
+ registerReturnValueHandlers(returnValueHandlers);
+ }
+ }
+
/**
* 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) {
+ public void setMessageConverters(List> messageConverters) {
this.messageConverters = messageConverters;
}
- /**
- * Set the {@link HandlerMethodArgumentResolver}s to use to resolve argument values for
- * {@link ExceptionHandler} methods. This is an optional property.
- * @param argumentResolvers the argument resolvers to use
- */
- public void setHandlerMethodArgumentResolvers(HandlerMethodArgumentResolver[] argumentResolvers) {
- this.argumentResolvers = new HandlerMethodArgumentResolverComposite();
+ public void afterPropertiesSet() throws Exception {
+ if (argumentResolvers == null) {
+ argumentResolvers = new HandlerMethodArgumentResolverComposite();
+ registerArgumentResolvers(customArgumentResolvers);
+ registerArgumentResolvers(getDefaultArgumentResolvers());
+ }
+ if (returnValueHandlers == null) {
+ returnValueHandlers = new HandlerMethodReturnValueHandlerComposite();
+ registerReturnValueHandlers(customReturnValueHandlers);
+ registerReturnValueHandlers(getDefaultReturnValueHandlers(messageConverters));
+ }
+ }
+
+ private void registerArgumentResolvers(List argumentResolvers) {
for (HandlerMethodArgumentResolver resolver : argumentResolvers) {
this.argumentResolvers.registerArgumentResolver(resolver);
}
}
- /**
- * Set the {@link HandlerMethodReturnValueHandler}s to use to handle the return values of
- * {@link ExceptionHandler} methods. This is an optional property.
- * @param returnValueHandlers the return value handlers to use
- */
- public void setHandlerMethodReturnValueHandlers(HandlerMethodReturnValueHandler[] returnValueHandlers) {
- this.returnValueHandlers = new HandlerMethodReturnValueHandlerComposite();
+ private void registerReturnValueHandlers(List returnValueHandlers) {
for (HandlerMethodReturnValueHandler handler : returnValueHandlers) {
this.returnValueHandlers.registerReturnValueHandler(handler);
}
}
- public void afterPropertiesSet() throws Exception {
- initMethodArgumentResolvers();
- initMethodReturnValueHandlers();
+ public static List getDefaultArgumentResolvers() {
+ List resolvers = new ArrayList();
+ resolvers.add(new ServletRequestMethodArgumentResolver());
+ resolvers.add(new ServletResponseMethodArgumentResolver());
+ return resolvers;
}
-
- private void initMethodArgumentResolvers() {
- if (argumentResolvers != null) {
- return;
- }
- argumentResolvers = new HandlerMethodArgumentResolverComposite();
+
+ public static List getDefaultReturnValueHandlers(
+ List> messageConverters) {
+
+ List handlers = new ArrayList();
- argumentResolvers.registerArgumentResolver(new ServletRequestMethodArgumentResolver());
- argumentResolvers.registerArgumentResolver(new ServletResponseMethodArgumentResolver());
-
- if (customArgumentResolvers != null) {
- for (WebArgumentResolver customResolver : customArgumentResolvers) {
- argumentResolvers.registerArgumentResolver(new ServletWebArgumentResolverAdapter(customResolver));
- }
- }
- }
-
- private void initMethodReturnValueHandlers() {
- if (returnValueHandlers != null) {
- return;
- }
- returnValueHandlers = new HandlerMethodReturnValueHandlerComposite();
-
// Annotation-based handlers
- returnValueHandlers.registerReturnValueHandler(new RequestResponseBodyMethodProcessor(messageConverters));
- returnValueHandlers.registerReturnValueHandler(new ModelAttributeMethodProcessor(false));
+ handlers.add(new RequestResponseBodyMethodProcessor(messageConverters));
+ handlers.add(new ModelAttributeMethodProcessor(false));
// Type-based handlers
- returnValueHandlers.registerReturnValueHandler(new ModelAndViewMethodReturnValueHandler());
- returnValueHandlers.registerReturnValueHandler(new ModelMethodProcessor());
- returnValueHandlers.registerReturnValueHandler(new ViewMethodReturnValueHandler());
- returnValueHandlers.registerReturnValueHandler(new HttpEntityMethodProcessor(messageConverters));
+ handlers.add(new ModelAndViewMethodReturnValueHandler());
+ handlers.add(new ModelMethodProcessor());
+ handlers.add(new ViewMethodReturnValueHandler());
+ handlers.add(new HttpEntityMethodProcessor(messageConverters));
// Default handler
- returnValueHandlers.registerReturnValueHandler(new DefaultMethodReturnValueHandler(null));
+ handlers.add(new DefaultMethodReturnValueHandler());
+
+ return handlers;
}
-
+
/**
* Attempts to find an {@link ExceptionHandler}-annotated method that can handle the thrown exception.
* The exception-handling method, if found, is invoked resulting in a {@link ModelAndView}.
diff --git a/org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/mvc/method/annotation/support/AbstractMessageConverterMethodProcessor.java b/org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/mvc/method/annotation/support/AbstractMessageConverterMethodProcessor.java
index 62754a241ae..8714b45f9f5 100644
--- a/org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/mvc/method/annotation/support/AbstractMessageConverterMethodProcessor.java
+++ b/org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/mvc/method/annotation/support/AbstractMessageConverterMethodProcessor.java
@@ -46,9 +46,9 @@ public abstract class AbstractMessageConverterMethodProcessor
protected final Log logger = LogFactory.getLog(getClass());
- private final HttpMessageConverter>[] messageConverters;
+ private final List> messageConverters;
- protected AbstractMessageConverterMethodProcessor(HttpMessageConverter>... messageConverters) {
+ protected AbstractMessageConverterMethodProcessor(List> messageConverters) {
Assert.notNull(messageConverters, "'messageConverters' must not be null");
this.messageConverters = messageConverters;
}
diff --git a/org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/mvc/method/annotation/support/DefaultMethodReturnValueHandler.java b/org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/mvc/method/annotation/support/DefaultMethodReturnValueHandler.java
index 01fd0b48481..b42a1c56303 100644
--- a/org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/mvc/method/annotation/support/DefaultMethodReturnValueHandler.java
+++ b/org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/mvc/method/annotation/support/DefaultMethodReturnValueHandler.java
@@ -17,6 +17,8 @@
package org.springframework.web.servlet.mvc.method.annotation.support;
import java.lang.reflect.Method;
+import java.util.ArrayList;
+import java.util.List;
import org.springframework.beans.BeanUtils;
import org.springframework.core.MethodParameter;
@@ -41,10 +43,22 @@ import org.springframework.web.servlet.mvc.annotation.ModelAndViewResolver;
*/
public class DefaultMethodReturnValueHandler implements HandlerMethodReturnValueHandler {
- private final ModelAndViewResolver[] customModelAndViewResolvers;
+ private final List modelAndViewResolvers = new ArrayList();
- public DefaultMethodReturnValueHandler(ModelAndViewResolver[] customResolvers) {
- this.customModelAndViewResolvers = (customResolvers != null) ? customResolvers : new ModelAndViewResolver[] {};
+ /**
+ * Create a {@link DefaultMethodReturnValueHandler} instance without {@link ModelAndViewResolver}s.
+ */
+ public DefaultMethodReturnValueHandler() {
+ this(null);
+ }
+
+ /**
+ * Create a {@link DefaultMethodReturnValueHandler} with a list of {@link ModelAndViewResolver}s.
+ */
+ public DefaultMethodReturnValueHandler(List modelAndViewResolvers) {
+ if (modelAndViewResolvers != null) {
+ this.modelAndViewResolvers.addAll(modelAndViewResolvers);
+ }
}
public boolean supportsReturnType(MethodParameter returnType) {
@@ -60,7 +74,7 @@ public class DefaultMethodReturnValueHandler implements HandlerMethodReturnValue
ModelAndViewContainer mavContainer,
NativeWebRequest webRequest) throws Exception {
- for (ModelAndViewResolver resolver : this.customModelAndViewResolvers) {
+ for (ModelAndViewResolver resolver : modelAndViewResolvers) {
Class> handlerType = returnType.getDeclaringClass();
Method method = returnType.getMethod();
ExtendedModelMap extModel = (ExtendedModelMap) mavContainer.getModel();
diff --git a/org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/mvc/method/annotation/support/HttpEntityMethodProcessor.java b/org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/mvc/method/annotation/support/HttpEntityMethodProcessor.java
index 66826bfc90a..cfa7a3eb4b4 100644
--- a/org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/mvc/method/annotation/support/HttpEntityMethodProcessor.java
+++ b/org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/mvc/method/annotation/support/HttpEntityMethodProcessor.java
@@ -21,6 +21,7 @@ import java.lang.reflect.Array;
import java.lang.reflect.GenericArrayType;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
+import java.util.List;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
@@ -53,7 +54,7 @@ import org.springframework.web.method.support.ModelAndViewContainer;
*/
public class HttpEntityMethodProcessor extends AbstractMessageConverterMethodProcessor {
- public HttpEntityMethodProcessor(HttpMessageConverter>... messageConverters) {
+ public HttpEntityMethodProcessor(List> messageConverters) {
super(messageConverters);
}
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 6e276b49b00..dc8795d6e68 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
@@ -17,6 +17,7 @@
package org.springframework.web.servlet.mvc.method.annotation.support;
import java.io.IOException;
+import java.util.List;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
@@ -47,7 +48,7 @@ import org.springframework.web.method.support.ModelAndViewContainer;
*/
public class RequestResponseBodyMethodProcessor extends AbstractMessageConverterMethodProcessor {
- public RequestResponseBodyMethodProcessor(HttpMessageConverter>... messageConverters) {
+ public RequestResponseBodyMethodProcessor(List> messageConverters) {
super(messageConverters);
}
diff --git a/org.springframework.web.servlet/src/test/java/org/springframework/web/servlet/config/AnnotationDrivenBeanDefinitionParserTests.java b/org.springframework.web.servlet/src/test/java/org/springframework/web/servlet/config/AnnotationDrivenBeanDefinitionParserTests.java
index 8830b91ae68..77cca9fc67f 100644
--- a/org.springframework.web.servlet/src/test/java/org/springframework/web/servlet/config/AnnotationDrivenBeanDefinitionParserTests.java
+++ b/org.springframework.web.servlet/src/test/java/org/springframework/web/servlet/config/AnnotationDrivenBeanDefinitionParserTests.java
@@ -19,6 +19,8 @@ import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
+import java.util.List;
+
import org.junit.Before;
import org.junit.Test;
import org.springframework.beans.DirectFieldAccessor;
@@ -31,10 +33,14 @@ import org.springframework.http.converter.StringHttpMessageConverter;
import org.springframework.validation.MessageCodesResolver;
import org.springframework.web.bind.support.ConfigurableWebBindingInitializer;
import org.springframework.web.bind.support.WebArgumentResolver;
+import org.springframework.web.bind.support.WebDataBinderFactory;
import org.springframework.web.context.request.NativeWebRequest;
import org.springframework.web.context.support.GenericWebApplicationContext;
+import org.springframework.web.method.support.HandlerMethodArgumentResolver;
+import org.springframework.web.method.support.ModelAndViewContainer;
import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMethodAdapter;
import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMethodExceptionResolver;
+import org.springframework.web.servlet.mvc.method.annotation.support.ServletWebArgumentResolverAdapter;
/**
* Test fixture for the configuration in mvc-config-annotation-driven.xml.
@@ -75,17 +81,19 @@ public class AnnotationDrivenBeanDefinitionParserTests {
verifyMessageConverters(appContext.getBean(RequestMappingHandlerMethodExceptionResolver.class), false);
}
+ @SuppressWarnings("unchecked")
@Test
public void testArgumentResolvers() {
loadBeanDefinitions("mvc-config-argument-resolvers.xml");
RequestMappingHandlerMethodAdapter adapter = appContext.getBean(RequestMappingHandlerMethodAdapter.class);
assertNotNull(adapter);
- Object resolvers = new DirectFieldAccessor(adapter).getPropertyValue("customArgumentResolvers");
- assertNotNull(resolvers);
- assertTrue(resolvers instanceof WebArgumentResolver[]);
- assertEquals(2, ((WebArgumentResolver[]) resolvers).length);
- assertTrue(((WebArgumentResolver[]) resolvers)[0] instanceof TestWebArgumentResolver);
- assertTrue(((WebArgumentResolver[]) resolvers)[1] instanceof TestWebArgumentResolver);
+ Object value = new DirectFieldAccessor(adapter).getPropertyValue("customArgumentResolvers");
+ assertNotNull(value);
+ assertTrue(value instanceof List);
+ List resolvers = (List) value;
+ assertEquals(2, resolvers.size());
+ assertTrue(resolvers.get(0) instanceof ServletWebArgumentResolverAdapter);
+ assertTrue(resolvers.get(1) instanceof TestHandlerMethodArgumentResolver);
}
private void loadBeanDefinitions(String fileName) {
@@ -95,20 +103,20 @@ public class AnnotationDrivenBeanDefinitionParserTests {
appContext.refresh();
}
+ @SuppressWarnings("unchecked")
private void verifyMessageConverters(Object bean, boolean hasDefaultRegistrations) {
assertNotNull(bean);
- Object converters = new DirectFieldAccessor(bean).getPropertyValue("messageConverters");
- assertNotNull(converters);
- assertTrue(converters instanceof HttpMessageConverter>[]);
+ Object value = new DirectFieldAccessor(bean).getPropertyValue("messageConverters");
+ assertNotNull(value);
+ assertTrue(value instanceof List);
+ List> converters = (List>) value;
if (hasDefaultRegistrations) {
- assertTrue("Default converters are registered in addition to custom ones",
- ((HttpMessageConverter>[]) converters).length > 2);
+ assertTrue("Default converters are registered in addition to custom ones", converters.size() > 2);
} else {
- assertTrue("Default converters should not be registered",
- ((HttpMessageConverter>[]) converters).length == 2);
+ assertTrue("Default converters should not be registered", converters.size() == 2);
}
- assertTrue(((HttpMessageConverter>[]) converters)[0] instanceof StringHttpMessageConverter);
- assertTrue(((HttpMessageConverter>[]) converters)[1] instanceof ResourceHttpMessageConverter);
+ assertTrue(converters.get(0) instanceof StringHttpMessageConverter);
+ assertTrue(converters.get(1) instanceof ResourceHttpMessageConverter);
}
}
@@ -121,6 +129,18 @@ class TestWebArgumentResolver implements WebArgumentResolver {
}
+class TestHandlerMethodArgumentResolver implements HandlerMethodArgumentResolver {
+
+ public boolean supportsParameter(MethodParameter parameter) {
+ return false;
+ }
+
+ public Object resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer,
+ NativeWebRequest webRequest, WebDataBinderFactory binderFactory) throws Exception {
+ return null;
+ }
+}
+
class TestMessageCodesResolver implements MessageCodesResolver {
public String[] resolveMessageCodes(String errorCode, String objectName) {
diff --git a/org.springframework.web.servlet/src/test/java/org/springframework/web/servlet/config/MvcAnnotationDrivenFeatureTests.java b/org.springframework.web.servlet/src/test/java/org/springframework/web/servlet/config/MvcAnnotationDrivenFeatureTests.java
index d0802f010b3..13e8abd2714 100644
--- a/org.springframework.web.servlet/src/test/java/org/springframework/web/servlet/config/MvcAnnotationDrivenFeatureTests.java
+++ b/org.springframework.web.servlet/src/test/java/org/springframework/web/servlet/config/MvcAnnotationDrivenFeatureTests.java
@@ -19,6 +19,8 @@ import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
+import java.util.List;
+
import org.junit.Test;
import org.springframework.beans.DirectFieldAccessor;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
@@ -35,8 +37,10 @@ import org.springframework.validation.Validator;
import org.springframework.validation.beanvalidation.LocalValidatorFactoryBean;
import org.springframework.web.bind.support.ConfigurableWebBindingInitializer;
import org.springframework.web.bind.support.WebArgumentResolver;
+import org.springframework.web.method.support.HandlerMethodArgumentResolver;
import org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter;
import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMethodAdapter;
+import org.springframework.web.servlet.mvc.method.annotation.support.ServletWebArgumentResolverAdapter;
/**
* Integration tests for the {@link MvcAnnotationDriven} feature specification.
@@ -46,6 +50,7 @@ import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandl
*/
public class MvcAnnotationDrivenFeatureTests {
+ @SuppressWarnings("unchecked")
@Test
public void testMessageCodesResolver() {
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext();
@@ -58,16 +63,17 @@ public class MvcAnnotationDrivenFeatureTests {
MessageCodesResolver resolver = ((ConfigurableWebBindingInitializer) initializer).getMessageCodesResolver();
assertNotNull(resolver);
assertEquals("test.foo.bar", resolver.resolveMessageCodes("foo", "bar")[0]);
- Object argResolvers = new DirectFieldAccessor(adapter).getPropertyValue("customArgumentResolvers");
- assertNotNull(argResolvers);
- WebArgumentResolver[] argResolversArray = (WebArgumentResolver[]) argResolvers;
- assertEquals(1, argResolversArray.length);
- assertTrue(argResolversArray[0] instanceof TestWebArgumentResolver);
+ Object value = new DirectFieldAccessor(adapter).getPropertyValue("customArgumentResolvers");
+ assertNotNull(value);
+ List resolvers = (List) value;
+ assertEquals(2, resolvers.size());
+ assertTrue(resolvers.get(0) instanceof ServletWebArgumentResolverAdapter);
+ assertTrue(resolvers.get(1) instanceof TestHandlerMethodArgumentResolver);
Object converters = new DirectFieldAccessor(adapter).getPropertyValue("messageConverters");
assertNotNull(converters);
- HttpMessageConverter>[] convertersArray = (HttpMessageConverter>[]) converters;
- assertTrue("Default converters are registered in addition to the custom one", convertersArray.length > 1);
- assertTrue(convertersArray[0] instanceof StringHttpMessageConverter);
+ List> convertersArray = (List>) converters;
+ assertTrue("Default converters are registered in addition to the custom one", convertersArray.size() > 1);
+ assertTrue(convertersArray.get(0) instanceof StringHttpMessageConverter);
}
}
@@ -81,7 +87,8 @@ class MvcFeature {
.messageCodesResolver(mvcBeans.messageCodesResolver())
.validator(mvcBeans.validator())
.messageConverters(new StringHttpMessageConverter())
- .argumentResolvers(new TestWebArgumentResolver());
+ .argumentResolvers(new TestWebArgumentResolver())
+ .argumentResolvers(new TestHandlerMethodArgumentResolver());
}
}
diff --git a/org.springframework.web.servlet/src/test/java/org/springframework/web/servlet/config/MvcNamespaceTests.java b/org.springframework.web.servlet/src/test/java/org/springframework/web/servlet/config/MvcNamespaceTests.java
index f583d7717d2..129cdc57f1e 100644
--- a/org.springframework.web.servlet/src/test/java/org/springframework/web/servlet/config/MvcNamespaceTests.java
+++ b/org.springframework.web.servlet/src/test/java/org/springframework/web/servlet/config/MvcNamespaceTests.java
@@ -25,6 +25,7 @@ import static org.junit.Assert.assertTrue;
import java.lang.reflect.Method;
import java.util.Date;
+import java.util.List;
import java.util.Locale;
import javax.servlet.RequestDispatcher;
@@ -111,8 +112,8 @@ public class MvcNamespaceTests {
RequestMappingHandlerMethodAdapter adapter = appContext.getBean(RequestMappingHandlerMethodAdapter.class);
assertNotNull(adapter);
- HttpMessageConverter>[] messageConverters = adapter.getMessageConverters();
- assertTrue(messageConverters.length > 0);
+ List> messageConverters = adapter.getMessageConverters();
+ assertTrue(messageConverters.size() > 0);
assertNotNull(appContext.getBean(FormattingConversionServiceFactoryBean.class));
assertNotNull(appContext.getBean(ConversionService.class));
diff --git a/org.springframework.web.servlet/src/test/java/org/springframework/web/servlet/mvc/method/annotation/RequestMappingHandlerMethodAdapterIntegrationTests.java b/org.springframework.web.servlet/src/test/java/org/springframework/web/servlet/mvc/method/annotation/RequestMappingHandlerMethodAdapterIntegrationTests.java
index 6dd785d9022..b425782b022 100644
--- a/org.springframework.web.servlet/src/test/java/org/springframework/web/servlet/mvc/method/annotation/RequestMappingHandlerMethodAdapterIntegrationTests.java
+++ b/org.springframework.web.servlet/src/test/java/org/springframework/web/servlet/mvc/method/annotation/RequestMappingHandlerMethodAdapterIntegrationTests.java
@@ -26,10 +26,12 @@ import java.awt.Color;
import java.lang.reflect.Method;
import java.security.Principal;
import java.text.SimpleDateFormat;
+import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.GregorianCalendar;
import java.util.HashMap;
+import java.util.List;
import java.util.Map;
import javax.servlet.http.Cookie;
@@ -74,10 +76,11 @@ import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletWebRequest;
import org.springframework.web.context.support.GenericWebApplicationContext;
import org.springframework.web.method.HandlerMethod;
+import org.springframework.web.method.support.HandlerMethodArgumentResolver;
import org.springframework.web.method.support.InvocableHandlerMethod;
import org.springframework.web.servlet.HandlerMapping;
import org.springframework.web.servlet.ModelAndView;
-import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMethodAdapter;
+import org.springframework.web.servlet.mvc.method.annotation.support.ServletWebArgumentResolverAdapter;
/**
* A test fixture for higher-level {@link RequestMappingHandlerMethodAdapter} tests.
@@ -109,9 +112,12 @@ public class RequestMappingHandlerMethodAdapterIntegrationTests {
ConfigurableWebBindingInitializer bindingInitializer = new ConfigurableWebBindingInitializer();
bindingInitializer.setValidator(new StubValidator());
+ List customResolvers = new ArrayList();
+ customResolvers.add(new ServletWebArgumentResolverAdapter(new ColorArgumentResolver()));
+
this.handlerAdapter = new RequestMappingHandlerMethodAdapter();
this.handlerAdapter.setWebBindingInitializer(bindingInitializer);
- this.handlerAdapter.setCustomArgumentResolvers(new WebArgumentResolver[] { new ColorArgumentResolver() });
+ this.handlerAdapter.setCustomArgumentResolvers(customResolvers);
GenericWebApplicationContext context = new GenericWebApplicationContext();
context.refresh();
diff --git a/org.springframework.web.servlet/src/test/java/org/springframework/web/servlet/mvc/method/annotation/ServletHandlerMethodTests.java b/org.springframework.web.servlet/src/test/java/org/springframework/web/servlet/mvc/method/annotation/ServletHandlerMethodTests.java
index 24d5eab977c..c8805fc8a09 100644
--- a/org.springframework.web.servlet/src/test/java/org/springframework/web/servlet/mvc/method/annotation/ServletHandlerMethodTests.java
+++ b/org.springframework.web.servlet/src/test/java/org/springframework/web/servlet/mvc/method/annotation/ServletHandlerMethodTests.java
@@ -1079,7 +1079,7 @@ public class ServletHandlerMethodTests {
public void register(GenericWebApplicationContext wac) {
RootBeanDefinition adapterDef = new RootBeanDefinition(RequestMappingHandlerMethodAdapter.class);
ModelAndViewResolver[] mavResolvers = new ModelAndViewResolver[] {new MyModelAndViewResolver()};
- adapterDef.getPropertyValues().add("customModelAndViewResolvers", mavResolvers);
+ adapterDef.getPropertyValues().add("modelAndViewResolvers", mavResolvers);
wac.registerBeanDefinition("handlerAdapter", adapterDef);
}
});
diff --git a/org.springframework.web.servlet/src/test/java/org/springframework/web/servlet/mvc/method/annotation/support/HttpEntityMethodProcessorTests.java b/org.springframework.web.servlet/src/test/java/org/springframework/web/servlet/mvc/method/annotation/support/HttpEntityMethodProcessorTests.java
index e1d8b39f6da..3b3a424a0c5 100644
--- a/org.springframework.web.servlet/src/test/java/org/springframework/web/servlet/mvc/method/annotation/support/HttpEntityMethodProcessorTests.java
+++ b/org.springframework.web.servlet/src/test/java/org/springframework/web/servlet/mvc/method/annotation/support/HttpEntityMethodProcessorTests.java
@@ -27,7 +27,9 @@ import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import java.lang.reflect.Method;
+import java.util.ArrayList;
import java.util.Arrays;
+import java.util.List;
import org.junit.Before;
import org.junit.Test;
@@ -82,7 +84,10 @@ public class HttpEntityMethodProcessorTests {
@Before
public void setUp() throws Exception {
messageConverter = createMock(HttpMessageConverter.class);
- processor = new HttpEntityMethodProcessor(messageConverter);
+
+ List> messageConverters = new ArrayList>();
+ messageConverters.add(messageConverter);
+ processor = new HttpEntityMethodProcessor(messageConverters);
Method handle1 = getClass().getMethod("handle1", HttpEntity.class, ResponseEntity.class, Integer.TYPE);
httpEntityParam = new MethodParameter(handle1, 0);
@@ -211,7 +216,9 @@ public class HttpEntityMethodProcessorTests {
responseHeaders.set("header", "headerValue");
ResponseEntity returnValue = new ResponseEntity(responseHeaders, HttpStatus.ACCEPTED);
- HttpEntityMethodProcessor processor = new HttpEntityMethodProcessor(new StringHttpMessageConverter());
+ List> messageConverters = new ArrayList>();
+ messageConverters.add(new StringHttpMessageConverter());
+ HttpEntityMethodProcessor processor = new HttpEntityMethodProcessor(messageConverters);
processor.handleReturnValue(returnValue, responseEntityReturnValue, mavContainer, request);
assertFalse(mavContainer.isResolveView());
@@ -224,7 +231,9 @@ public class HttpEntityMethodProcessorTests {
responseHeaders.set("header", "headerValue");
ResponseEntity returnValue = new ResponseEntity("body", responseHeaders, HttpStatus.ACCEPTED);
- HttpEntityMethodProcessor processor = new HttpEntityMethodProcessor(new StringHttpMessageConverter());
+ List> messageConverters = new ArrayList>();
+ messageConverters.add(new StringHttpMessageConverter());
+ HttpEntityMethodProcessor processor = new HttpEntityMethodProcessor(messageConverters);
processor.handleReturnValue(returnValue, responseEntityReturnValue, mavContainer, request);
assertFalse(mavContainer.isResolveView());
diff --git a/org.springframework.web.servlet/src/test/java/org/springframework/web/servlet/mvc/method/annotation/support/RequestResponseBodyMethodProcessorTests.java b/org.springframework.web.servlet/src/test/java/org/springframework/web/servlet/mvc/method/annotation/support/RequestResponseBodyMethodProcessorTests.java
index e446b04e7fa..016a222f2ed 100644
--- a/org.springframework.web.servlet/src/test/java/org/springframework/web/servlet/mvc/method/annotation/support/RequestResponseBodyMethodProcessorTests.java
+++ b/org.springframework.web.servlet/src/test/java/org/springframework/web/servlet/mvc/method/annotation/support/RequestResponseBodyMethodProcessorTests.java
@@ -27,7 +27,9 @@ import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import java.lang.reflect.Method;
+import java.util.ArrayList;
import java.util.Arrays;
+import java.util.List;
import org.junit.Before;
import org.junit.Test;
@@ -45,7 +47,6 @@ import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.context.request.NativeWebRequest;
import org.springframework.web.context.request.ServletWebRequest;
import org.springframework.web.method.support.ModelAndViewContainer;
-import org.springframework.web.servlet.mvc.method.annotation.support.RequestResponseBodyMethodProcessor;
/**
* @author Arjen Poutsma
@@ -74,7 +75,11 @@ public class RequestResponseBodyMethodProcessorTests {
@Before
public void setUp() throws Exception {
messageConverter = createMock(HttpMessageConverter.class);
- processor = new RequestResponseBodyMethodProcessor(messageConverter);
+
+ List> messageConverters = new ArrayList>();
+ messageConverters.add(messageConverter);
+ processor = new RequestResponseBodyMethodProcessor(messageConverters);
+
Method handle = getClass().getMethod("handle", String.class, Integer.TYPE);
stringParameter = new MethodParameter(handle, 0);
intParameter = new MethodParameter(handle, 1);
diff --git a/org.springframework.web.servlet/src/test/resources/org/springframework/web/servlet/config/mvc-config-argument-resolvers.xml b/org.springframework.web.servlet/src/test/resources/org/springframework/web/servlet/config/mvc-config-argument-resolvers.xml
index 7521bb0e698..2fbbda75b2e 100644
--- a/org.springframework.web.servlet/src/test/resources/org/springframework/web/servlet/config/mvc-config-argument-resolvers.xml
+++ b/org.springframework.web.servlet/src/test/resources/org/springframework/web/servlet/config/mvc-config-argument-resolvers.xml
@@ -8,7 +8,7 @@
-
+