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 @@ - +