SPR-8234 Argument resolver and return value handler configuration improvements
This commit is contained in:
parent
68b4687311
commit
313546ad1f
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
*
|
||||
* <p>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.
|
||||
* <p>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.
|
||||
*
|
||||
* <p>{@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.
|
||||
* <p>{@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}.
|
||||
*
|
||||
* <p>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.
|
||||
* <p>{@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.
|
||||
*
|
||||
* <p>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}.
|
||||
* <p>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<HandlerMethodArgumentResolver> customArgumentResolvers =
|
||||
new ArrayList<HandlerMethodArgumentResolver>();
|
||||
|
||||
private ModelAndViewResolver[] customModelAndViewResolvers;
|
||||
private final List<HandlerMethodReturnValueHandler> customReturnValueHandlers =
|
||||
new ArrayList<HandlerMethodReturnValueHandler>();
|
||||
|
||||
private HttpMessageConverter<?>[] messageConverters;
|
||||
private final List<ModelAndViewResolver> modelAndViewResolvers = new ArrayList<ModelAndViewResolver>();
|
||||
|
||||
private List<HttpMessageConverter<?>> 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<Source>(),
|
||||
new XmlAwareFormHttpMessageConverter() };
|
||||
messageConverters = new ArrayList<HttpMessageConverter<?>>();
|
||||
messageConverters.add(new ByteArrayHttpMessageConverter());
|
||||
messageConverters.add(stringHttpMessageConverter);
|
||||
messageConverters.add(new SourceHttpMessageConverter<Source>());
|
||||
messageConverters.add(new XmlAwareFormHttpMessageConverter());
|
||||
}
|
||||
|
||||
/**
|
||||
* Set one or more custom WebArgumentResolvers to use for special method parameter types.
|
||||
* <p>Any such custom WebArgumentResolver will kick in first, having a chance to resolve
|
||||
* an argument value before the standard argument handling kicks in.
|
||||
* <p>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.
|
||||
* <p>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<HandlerMethodArgumentResolver> adaptedResolvers = new ArrayList<HandlerMethodArgumentResolver>();
|
||||
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 one or more custom ModelAndViewResolvers to use for special method return types.
|
||||
* <p>Any such custom ModelAndViewResolver will kick in first, having a chance to resolve
|
||||
* a return value before the standard ModelAndView handling kicks in.
|
||||
* <p>Note: this is provided for backward compatibility. The preferred way to do this is to
|
||||
* implement a {@link HandlerMethodReturnValueHandler}.
|
||||
* 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 setCustomModelAndViewResolvers(ModelAndViewResolver[] customModelAndViewResolvers) {
|
||||
this.customModelAndViewResolvers = customModelAndViewResolvers;
|
||||
public void setArgumentResolvers(List<HandlerMethodArgumentResolver> 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<HandlerMethodArgumentResolver> argumentResolvers) {
|
||||
if (argumentResolvers != null) {
|
||||
this.initBinderArgumentResolvers = new HandlerMethodArgumentResolverComposite();
|
||||
registerInitBinderArgumentResolvers(argumentResolvers);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 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 setCustomReturnValueHandlers(List<HandlerMethodReturnValueHandler> 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<HandlerMethodReturnValueHandler> 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.
|
||||
* <p>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<ModelAndViewResolver> modelAndViewResolvers) {
|
||||
if (modelAndViewResolvers != null) {
|
||||
this.modelAndViewResolvers.addAll(modelAndViewResolvers);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the message body converters to use.
|
||||
* <p>These converters are used to convert from and to HTTP requests and responses.
|
||||
*/
|
||||
public void setMessageConverters(HttpMessageConverter<?>[] messageConverters) {
|
||||
public void setMessageConverters(List<HttpMessageConverter<?>> messageConverters) {
|
||||
this.messageConverters = messageConverters;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the message body converters that this adapter has been configured with.
|
||||
*/
|
||||
public HttpMessageConverter<?>[] getMessageConverters() {
|
||||
public List<HttpMessageConverter<?>> 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<HandlerMethodArgumentResolver> 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));
|
||||
}
|
||||
private void registerInitBinderArgumentResolvers(List<HandlerMethodArgumentResolver> argumentResolvers) {
|
||||
for (HandlerMethodArgumentResolver resolver : argumentResolvers) {
|
||||
this.initBinderArgumentResolvers.registerArgumentResolver(resolver);
|
||||
}
|
||||
}
|
||||
|
||||
private void registerReturnValueHandlers(List<HandlerMethodReturnValueHandler> returnValueHandlers) {
|
||||
for (HandlerMethodReturnValueHandler handler : returnValueHandlers) {
|
||||
this.returnValueHandlers.registerReturnValueHandler(handler);
|
||||
}
|
||||
}
|
||||
|
||||
public static List<HandlerMethodArgumentResolver> getDefaultArgumentResolvers(
|
||||
List<HttpMessageConverter<?>> messageConverters, ConfigurableBeanFactory beanFactory) {
|
||||
|
||||
List<HandlerMethodArgumentResolver> resolvers = new ArrayList<HandlerMethodArgumentResolver>();
|
||||
|
||||
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
|
||||
argumentResolvers.registerArgumentResolver(new ServletRequestMethodArgumentResolver());
|
||||
argumentResolvers.registerArgumentResolver(new ServletResponseMethodArgumentResolver());
|
||||
argumentResolvers.registerArgumentResolver(new HttpEntityMethodProcessor(messageConverters));
|
||||
argumentResolvers.registerArgumentResolver(new ModelMethodProcessor());
|
||||
argumentResolvers.registerArgumentResolver(new ErrorsMethodArgumentResolver());
|
||||
resolvers.add(new ServletRequestMethodArgumentResolver());
|
||||
resolvers.add(new ServletResponseMethodArgumentResolver());
|
||||
resolvers.add(new HttpEntityMethodProcessor(messageConverters));
|
||||
resolvers.add(new ModelMethodProcessor());
|
||||
resolvers.add(new ErrorsMethodArgumentResolver());
|
||||
|
||||
// Default-mode resolution
|
||||
argumentResolvers.registerArgumentResolver(new RequestParamMethodArgumentResolver(beanFactory, true));
|
||||
argumentResolvers.registerArgumentResolver(new ServletModelAttributeMethodProcessor(true));
|
||||
resolvers.add(new RequestParamMethodArgumentResolver(beanFactory, true));
|
||||
resolvers.add(new ServletModelAttributeMethodProcessor(true));
|
||||
|
||||
return resolvers;
|
||||
}
|
||||
|
||||
private void initBinderMethodArgumentResolvers() {
|
||||
if (initBinderArgumentResolvers != null) {
|
||||
return;
|
||||
}
|
||||
initBinderArgumentResolvers = new HandlerMethodArgumentResolverComposite();
|
||||
public static List<HandlerMethodArgumentResolver> getDefaultInitBinderArgumentResolvers(
|
||||
ConfigurableBeanFactory beanFactory) {
|
||||
|
||||
List<HandlerMethodArgumentResolver> resolvers = new ArrayList<HandlerMethodArgumentResolver>();
|
||||
|
||||
// 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));
|
||||
}
|
||||
}
|
||||
resolvers.add(new RequestParamMethodArgumentResolver(beanFactory, false));
|
||||
resolvers.add(new RequestParamMapMethodArgumentResolver());
|
||||
resolvers.add(new PathVariableMethodArgumentResolver(beanFactory));
|
||||
resolvers.add(new ExpressionValueMethodArgumentResolver(beanFactory));
|
||||
|
||||
// Type-based resolvers
|
||||
initBinderArgumentResolvers.registerArgumentResolver(new ServletRequestMethodArgumentResolver());
|
||||
initBinderArgumentResolvers.registerArgumentResolver(new ServletResponseMethodArgumentResolver());
|
||||
resolvers.add(new ServletRequestMethodArgumentResolver());
|
||||
resolvers.add(new ServletResponseMethodArgumentResolver());
|
||||
|
||||
// Default-mode resolution
|
||||
initBinderArgumentResolvers.registerArgumentResolver(new RequestParamMethodArgumentResolver(beanFactory, true));
|
||||
resolvers.add(new RequestParamMethodArgumentResolver(beanFactory, true));
|
||||
|
||||
return resolvers;
|
||||
}
|
||||
|
||||
private void initHandlerMethodReturnValueHandlers() {
|
||||
if (returnValueHandlers != null) {
|
||||
return;
|
||||
}
|
||||
returnValueHandlers = new HandlerMethodReturnValueHandlerComposite();
|
||||
public static List<HandlerMethodReturnValueHandler> getDefaultReturnValueHandlers(
|
||||
List<HttpMessageConverter<?>> messageConverters, List<ModelAndViewResolver> modelAndViewResolvers) {
|
||||
|
||||
List<HandlerMethodReturnValueHandler> handlers = new ArrayList<HandlerMethodReturnValueHandler>();
|
||||
|
||||
// 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
|
||||
|
|
|
|||
|
|
@ -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<HandlerMethodArgumentResolver> customArgumentResolvers =
|
||||
new ArrayList<HandlerMethodArgumentResolver>();
|
||||
|
||||
private HttpMessageConverter<?>[] messageConverters;
|
||||
private final List<HandlerMethodReturnValueHandler> customReturnValueHandlers =
|
||||
new ArrayList<HandlerMethodReturnValueHandler>();
|
||||
|
||||
private List<HttpMessageConverter<?>> messageConverters;
|
||||
|
||||
private final Map<Class<?>, ExceptionMethodMapping> exceptionMethodMappingCache =
|
||||
new ConcurrentHashMap<Class<?>, ExceptionMethodMapping>();
|
||||
|
|
@ -99,93 +105,137 @@ public class RequestMappingHandlerMethodExceptionResolver extends AbstractHandle
|
|||
StringHttpMessageConverter stringHttpMessageConverter = new StringHttpMessageConverter();
|
||||
stringHttpMessageConverter.setWriteAcceptCharset(false); // See SPR-7316
|
||||
|
||||
this.messageConverters = new HttpMessageConverter[] { new ByteArrayHttpMessageConverter(),
|
||||
stringHttpMessageConverter, new SourceHttpMessageConverter<Source>(),
|
||||
new XmlAwareFormHttpMessageConverter() };
|
||||
messageConverters = new ArrayList<HttpMessageConverter<?>>();
|
||||
messageConverters.add(new ByteArrayHttpMessageConverter());
|
||||
messageConverters.add(stringHttpMessageConverter);
|
||||
messageConverters.add(new SourceHttpMessageConverter<Source>());
|
||||
messageConverters.add(new XmlAwareFormHttpMessageConverter());
|
||||
}
|
||||
|
||||
/**
|
||||
* Set one or more custom ArgumentResolvers to use for special method parameter types.
|
||||
* <p>Any such custom ArgumentResolver will kick in first, having a chance to resolve
|
||||
* an argument value before the standard argument handling kicks in.
|
||||
* <p>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.
|
||||
* <p>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<HandlerMethodArgumentResolver> adaptedResolvers = new ArrayList<HandlerMethodArgumentResolver>();
|
||||
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<HandlerMethodArgumentResolver> 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<HandlerMethodReturnValueHandler> 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<HandlerMethodReturnValueHandler> returnValueHandlers) {
|
||||
if (returnValueHandlers != null) {
|
||||
this.returnValueHandlers = new HandlerMethodReturnValueHandlerComposite();
|
||||
registerReturnValueHandlers(returnValueHandlers);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the message body converters to use.
|
||||
* <p>These converters are used to convert from and to HTTP requests and responses.
|
||||
*/
|
||||
public void setMessageConverters(HttpMessageConverter<?>[] messageConverters) {
|
||||
public void setMessageConverters(List<HttpMessageConverter<?>> 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<HandlerMethodArgumentResolver> 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<HandlerMethodReturnValueHandler> returnValueHandlers) {
|
||||
for (HandlerMethodReturnValueHandler handler : returnValueHandlers) {
|
||||
this.returnValueHandlers.registerReturnValueHandler(handler);
|
||||
}
|
||||
}
|
||||
|
||||
public void afterPropertiesSet() throws Exception {
|
||||
initMethodArgumentResolvers();
|
||||
initMethodReturnValueHandlers();
|
||||
public static List<HandlerMethodArgumentResolver> getDefaultArgumentResolvers() {
|
||||
List<HandlerMethodArgumentResolver> resolvers = new ArrayList<HandlerMethodArgumentResolver>();
|
||||
resolvers.add(new ServletRequestMethodArgumentResolver());
|
||||
resolvers.add(new ServletResponseMethodArgumentResolver());
|
||||
return resolvers;
|
||||
}
|
||||
|
||||
private void initMethodArgumentResolvers() {
|
||||
if (argumentResolvers != null) {
|
||||
return;
|
||||
}
|
||||
argumentResolvers = new HandlerMethodArgumentResolverComposite();
|
||||
public static List<HandlerMethodReturnValueHandler> getDefaultReturnValueHandlers(
|
||||
List<HttpMessageConverter<?>> messageConverters) {
|
||||
|
||||
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();
|
||||
List<HandlerMethodReturnValueHandler> handlers = new ArrayList<HandlerMethodReturnValueHandler>();
|
||||
|
||||
// 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;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -46,9 +46,9 @@ public abstract class AbstractMessageConverterMethodProcessor
|
|||
|
||||
protected final Log logger = LogFactory.getLog(getClass());
|
||||
|
||||
private final HttpMessageConverter<?>[] messageConverters;
|
||||
private final List<HttpMessageConverter<?>> messageConverters;
|
||||
|
||||
protected AbstractMessageConverterMethodProcessor(HttpMessageConverter<?>... messageConverters) {
|
||||
protected AbstractMessageConverterMethodProcessor(List<HttpMessageConverter<?>> messageConverters) {
|
||||
Assert.notNull(messageConverters, "'messageConverters' must not be null");
|
||||
this.messageConverters = messageConverters;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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<ModelAndViewResolver> modelAndViewResolvers = new ArrayList<ModelAndViewResolver>();
|
||||
|
||||
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<ModelAndViewResolver> 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();
|
||||
|
|
|
|||
|
|
@ -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<HttpMessageConverter<?>> messageConverters) {
|
||||
super(messageConverters);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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<HttpMessageConverter<?>> messageConverters) {
|
||||
super(messageConverters);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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<HandlerMethodArgumentResolver> resolvers = (List<HandlerMethodArgumentResolver>) 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<HttpMessageConverter<?>> converters = (List<HttpMessageConverter<?>>) 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) {
|
||||
|
|
|
|||
|
|
@ -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<HandlerMethodArgumentResolver> resolvers = (List<HandlerMethodArgumentResolver>) 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<HttpMessageConverter<?>> convertersArray = (List<HttpMessageConverter<?>>) 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());
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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<HttpMessageConverter<?>> messageConverters = adapter.getMessageConverters();
|
||||
assertTrue(messageConverters.size() > 0);
|
||||
|
||||
assertNotNull(appContext.getBean(FormattingConversionServiceFactoryBean.class));
|
||||
assertNotNull(appContext.getBean(ConversionService.class));
|
||||
|
|
|
|||
|
|
@ -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<HandlerMethodArgumentResolver> customResolvers = new ArrayList<HandlerMethodArgumentResolver>();
|
||||
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();
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
});
|
||||
|
|
|
|||
|
|
@ -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<HttpMessageConverter<?>> messageConverters = new ArrayList<HttpMessageConverter<?>>();
|
||||
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<String> returnValue = new ResponseEntity<String>(responseHeaders, HttpStatus.ACCEPTED);
|
||||
|
||||
HttpEntityMethodProcessor processor = new HttpEntityMethodProcessor(new StringHttpMessageConverter());
|
||||
List<HttpMessageConverter<?>> messageConverters = new ArrayList<HttpMessageConverter<?>>();
|
||||
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<String> returnValue = new ResponseEntity<String>("body", responseHeaders, HttpStatus.ACCEPTED);
|
||||
|
||||
HttpEntityMethodProcessor processor = new HttpEntityMethodProcessor(new StringHttpMessageConverter());
|
||||
List<HttpMessageConverter<?>> messageConverters = new ArrayList<HttpMessageConverter<?>>();
|
||||
messageConverters.add(new StringHttpMessageConverter());
|
||||
HttpEntityMethodProcessor processor = new HttpEntityMethodProcessor(messageConverters);
|
||||
processor.handleReturnValue(returnValue, responseEntityReturnValue, mavContainer, request);
|
||||
|
||||
assertFalse(mavContainer.isResolveView());
|
||||
|
|
|
|||
|
|
@ -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<HttpMessageConverter<?>> messageConverters = new ArrayList<HttpMessageConverter<?>>();
|
||||
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);
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@
|
|||
<mvc:annotation-driven>
|
||||
<mvc:argument-resolvers>
|
||||
<bean class="org.springframework.web.servlet.config.TestWebArgumentResolver"/>
|
||||
<bean class="org.springframework.web.servlet.config.TestWebArgumentResolver"/>
|
||||
<bean class="org.springframework.web.servlet.config.TestHandlerMethodArgumentResolver"/>
|
||||
</mvc:argument-resolvers>
|
||||
</mvc:annotation-driven>
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue