diff --git a/org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/config/annotation/WebMvcConfigurer.java b/org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/config/annotation/WebMvcConfigurer.java
index 665b9325df..cc86beb8b7 100644
--- a/org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/config/annotation/WebMvcConfigurer.java
+++ b/org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/config/annotation/WebMvcConfigurer.java
@@ -23,22 +23,20 @@ import org.springframework.format.Formatter;
import org.springframework.format.FormatterRegistry;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.validation.Validator;
-import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.method.support.HandlerMethodArgumentResolver;
import org.springframework.web.method.support.HandlerMethodReturnValueHandler;
import org.springframework.web.servlet.DispatcherServlet;
import org.springframework.web.servlet.HandlerExceptionResolver;
import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter;
-import com.sun.corba.se.impl.presentation.rmi.ExceptionHandler;
-
/**
- * Defines configuration callback methods for customizing the default Spring MVC code-based configuration enabled
- * through @{@link EnableWebMvc}.
+ * Defines callback methods to customize the Java-based configuration for
+ * Spring MVC enabled via {@code @EnableWebMvc}.
*
- *
Classes annotated with @{@link EnableWebMvc} can implement this interface in order to be called back and
- * given a chance to customize the default configuration. The most convenient way to implement this interface
- * is to extend {@link WebMvcConfigurerAdapter}, which provides empty method implementations.
+ *
{@code @EnableWebMvc}-annotated configuration classes may implement
+ * this interface to be called back and given a chance to customize the
+ * default configuration. Consider extending {@link WebMvcConfigurerAdapter},
+ * which provides a stub implementation of all interface methods.
*
* @author Rossen Stoyanchev
* @author Keith Donald
@@ -48,78 +46,79 @@ import com.sun.corba.se.impl.presentation.rmi.ExceptionHandler;
public interface WebMvcConfigurer {
/**
- * Add {@link Converter}s and {@link Formatter}s in addition to the ones registered by default.
+ * Add {@link Converter}s and {@link Formatter}s in addition to the ones
+ * registered by default.
*/
void addFormatters(FormatterRegistry registry);
/**
- * Configure the list of {@link HttpMessageConverter}s to use when resolving method arguments or handling
- * return values in @{@link RequestMapping} and @{@link ExceptionHandler} methods.
- * Adding converters to the list turns off the default converters that would otherwise be registered by default.
- * @param converters a list to add message converters to; initially an empty list.
+ * Configure the {@link HttpMessageConverter}s to use in argument resolvers
+ * and return value handlers that support reading and/or writing to the
+ * body of the request and response. If no message converters are added to
+ * the list, default converters are added instead.
+ * @param converters initially an empty list of converters
*/
void configureMessageConverters(List> converters);
/**
- * Provide a custom {@link Validator} type replacing the one that would be created by default otherwise. If this
- * method returns {@code null}, and assuming a JSR-303 implementation is available on the classpath, a validator
- * of type {@link org.springframework.validation.beanvalidation.LocalValidatorFactoryBean} is created by default.
+ * Provide a custom {@link Validator} instead of the one created by default.
+ * The default implementation, assuming JSR-303 is on the classpath, is:
+ * {@link org.springframework.validation.beanvalidation.LocalValidatorFactoryBean}.
+ * Leave the return value as {@code null} to keep the default.
*/
Validator getValidator();
/**
- * Add custom {@link HandlerMethodArgumentResolver}s to use in addition to the ones registered by default.
- *
Custom argument resolvers are invoked before built-in resolvers except for those that rely on the presence
- * of annotations (e.g. {@code @RequestParameter}, {@code @PathVariable}, etc.). The latter can be customized
- * by configuring the {@link RequestMappingHandlerAdapter} directly.
- * @param argumentResolvers the list of custom converters; initially an empty list.
+ * Add resolvers to support custom controller method argument types.
+ *
This does not override the built-in support for resolving handler
+ * method arguments. To customize the built-in support for argument
+ * resolution, configure {@link RequestMappingHandlerAdapter} directly.
+ * @param argumentResolvers initially an empty list
*/
void addArgumentResolvers(List argumentResolvers);
/**
- * Add custom {@link HandlerMethodReturnValueHandler}s in addition to the ones registered by default.
- *
Custom return value handlers are invoked before built-in ones except for those that rely on the presence
- * of annotations (e.g. {@code @ResponseBody}, {@code @ModelAttribute}, etc.). The latter can be customized
- * by configuring the {@link RequestMappingHandlerAdapter} directly.
- * @param returnValueHandlers the list of custom handlers; initially an empty list.
+ * Add handlers to support custom controller method return value types.
+ *
Using this option does not override the built-in support for handling
+ * return values. To customize the built-in support for handling return
+ * values, configure RequestMappingHandlerAdapter directly.
+ * @param returnValueHandlers initially an empty list
*/
void addReturnValueHandlers(List returnValueHandlers);
/**
- * Configure the list of {@link HandlerExceptionResolver}s to use for handling unresolved controller exceptions.
- * Adding resolvers to the list turns off the default resolvers that would otherwise be registered by default.
- * @param exceptionResolvers a list to add exception resolvers to; initially an empty list.
+ * Configure the {@link HandlerExceptionResolver}s to handle unresolved
+ * controller exceptions. If no resolvers are added to the list, default
+ * exception resolvers are added instead.
+ * @param exceptionResolvers initially an empty list
*/
void configureHandlerExceptionResolvers(List exceptionResolvers);
/**
- * Add Spring MVC lifecycle interceptors for pre- and post-processing of controller method invocations.
- * Interceptors can be registered to apply to all requests or to a set of URL path patterns.
- * @see InterceptorRegistry
+ * Add Spring MVC lifecycle interceptors for pre- and post-processing of
+ * controller method invocations. Interceptors can be registered to apply
+ * to all requests or be limited to a subset of URL patterns.
*/
void addInterceptors(InterceptorRegistry registry);
/**
- * Add view controllers to create a direct mapping between a URL path and view name. This is useful when
- * you just want to forward the request to a view such as a JSP without the need for controller logic.
- * @see ViewControllerRegistry
+ * Add view controllers to create a direct mapping between a URL path and
+ * view name without the need for a controller in between.
*/
void addViewControllers(ViewControllerRegistry registry);
/**
- * Add resource handlers to use to serve static resources such as images, js, and, css files through
- * the Spring MVC {@link DispatcherServlet} including the setting of cache headers optimized for efficient
- * loading in a web browser. Resources can be served out of locations under web application root,
- * from the classpath, and others.
- * @see ResourceHandlerRegistry
+ * Add handlers to serve static resources such as images, js, and, css
+ * files from specific locations under web application root, the classpath,
+ * and others.
*/
void addResourceHandlers(ResourceHandlerRegistry registry);
/**
- * Configure a handler for delegating unhandled requests by forwarding to the Servlet container's "default"
- * servlet. The use case for this is when the {@link DispatcherServlet} is mapped to "/" thus overriding
- * the Servlet container's default handling of static resources.
- * @see DefaultServletHandlerConfigurer
+ * Configure a handler to delegate unhandled requests by forwarding to the
+ * Servlet container's "default" servlet. A common use case for this is when
+ * the {@link DispatcherServlet} is mapped to "/" thus overriding the
+ * Servlet container's default handling of static resources.
*/
void configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer);
diff --git a/org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/mvc/method/AbstractHandlerMethodAdapter.java b/org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/mvc/method/AbstractHandlerMethodAdapter.java
index 3246388be4..653628ceaa 100644
--- a/org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/mvc/method/AbstractHandlerMethodAdapter.java
+++ b/org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/mvc/method/AbstractHandlerMethodAdapter.java
@@ -26,8 +26,8 @@ import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.support.WebContentGenerator;
/**
- * Abstract base class for {@link HandlerAdapter} implementations that support the handling of requests through
- * the execution of {@link HandlerMethod}s rather than handlers.
+ * Abstract base class for {@link HandlerAdapter} implementations that support
+ * handlers of type {@link HandlerMethod}.
*
* @author Arjen Poutsma
* @since 3.1
diff --git a/org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/mvc/method/annotation/RequestMappingHandlerAdapter.java b/org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/mvc/method/annotation/RequestMappingHandlerAdapter.java
index 4ce707ea9e..f7b7ae2cad 100644
--- a/org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/mvc/method/annotation/RequestMappingHandlerAdapter.java
+++ b/org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/mvc/method/annotation/RequestMappingHandlerAdapter.java
@@ -43,16 +43,12 @@ import org.springframework.http.converter.xml.XmlAwareFormHttpMessageConverter;
import org.springframework.ui.Model;
import org.springframework.ui.ModelMap;
import org.springframework.util.ReflectionUtils.MethodFilter;
-import org.springframework.validation.DataBinder;
-import org.springframework.web.bind.WebDataBinder;
import org.springframework.web.bind.annotation.InitBinder;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.support.DefaultDataBinderFactory;
import org.springframework.web.bind.support.DefaultSessionAttributeStore;
import org.springframework.web.bind.support.SessionAttributeStore;
-import org.springframework.web.bind.support.SessionStatus;
-import org.springframework.web.bind.support.SimpleSessionStatus;
import org.springframework.web.bind.support.WebBindingInitializer;
import org.springframework.web.bind.support.WebDataBinderFactory;
import org.springframework.web.context.request.ServletWebRequest;
@@ -63,12 +59,14 @@ import org.springframework.web.method.annotation.ModelFactory;
import org.springframework.web.method.annotation.SessionAttributesHandler;
import org.springframework.web.method.annotation.support.ErrorsMethodArgumentResolver;
import org.springframework.web.method.annotation.support.ExpressionValueMethodArgumentResolver;
+import org.springframework.web.method.annotation.support.MapMethodProcessor;
import org.springframework.web.method.annotation.support.ModelAttributeMethodProcessor;
import org.springframework.web.method.annotation.support.ModelMethodProcessor;
import org.springframework.web.method.annotation.support.RequestHeaderMapMethodArgumentResolver;
import org.springframework.web.method.annotation.support.RequestHeaderMethodArgumentResolver;
import org.springframework.web.method.annotation.support.RequestParamMapMethodArgumentResolver;
import org.springframework.web.method.annotation.support.RequestParamMethodArgumentResolver;
+import org.springframework.web.method.annotation.support.SessionStatusMethodArgumentResolver;
import org.springframework.web.method.support.HandlerMethodArgumentResolver;
import org.springframework.web.method.support.HandlerMethodArgumentResolverComposite;
import org.springframework.web.method.support.HandlerMethodReturnValueHandler;
@@ -77,7 +75,6 @@ import org.springframework.web.method.support.InvocableHandlerMethod;
import org.springframework.web.method.support.ModelAndViewContainer;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.View;
-import org.springframework.web.servlet.mvc.LastModified;
import org.springframework.web.servlet.mvc.annotation.ModelAndViewResolver;
import org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter;
import org.springframework.web.servlet.mvc.method.annotation.support.DefaultMethodReturnValueHandler;
@@ -92,36 +89,25 @@ import org.springframework.web.servlet.mvc.method.annotation.support.ServletMode
import org.springframework.web.servlet.mvc.method.annotation.support.ServletRequestMethodArgumentResolver;
import org.springframework.web.servlet.mvc.method.annotation.support.ServletResponseMethodArgumentResolver;
import org.springframework.web.servlet.mvc.method.annotation.support.ViewMethodReturnValueHandler;
+import org.springframework.web.servlet.mvc.method.annotation.support.ViewNameMethodReturnValueHandler;
import org.springframework.web.servlet.mvc.support.RedirectAttributes;
import org.springframework.web.servlet.support.RequestContextUtils;
import org.springframework.web.util.WebUtils;
/**
- * An {@link AbstractHandlerMethodAdapter} variant with support for {@link RequestMapping} handler methods.
- *
- *
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 contributor that helps with the invocation of handler
- * methods of all types resolving their arguments through registered {@link HandlerMethodArgumentResolver}s.
- * {@link ServletInvocableHandlerMethod} on the other hand adds handling of the return value for
- * {@link RequestMapping} methods through registered {@link HandlerMethodReturnValueHandler}s
- * resulting in a {@link ModelAndView}.
- *
- *
{@link ModelFactory} is another contributor that assists with the invocation of all {@link ModelAttribute}
- * methods to populate a model while {@link ServletRequestDataBinderFactory} assists with the invocation of
- * {@link InitBinder} methods for initializing data binder instances when needed.
- *
- *
This class is the central point that assembles all mentioned contributors and invokes the actual
- * {@link RequestMapping} handler method through a {@link ServletInvocableHandlerMethod}.
+ * An {@link AbstractHandlerMethodAdapter} that supports {@link HandlerMethod}s
+ * with the signature -- method argument and return types, defined in
+ * {@code @RequestMapping}.
+ *
+ *
Support for custom argument and return value types can be added via
+ * {@link #setCustomArgumentResolvers} and {@link #setCustomReturnValueHandlers}.
+ * Or alternatively to re-configure all argument and return value types use
+ * {@link #setArgumentResolvers} and {@link #setReturnValueHandlers(List)}.
*
* @author Rossen Stoyanchev
* @since 3.1
* @see HandlerMethodArgumentResolver
* @see HandlerMethodReturnValueHandler
- * @see #setCustomArgumentResolvers(List)
- * @see #setCustomReturnValueHandlers(List)
*/
public class RequestMappingHandlerAdapter extends AbstractHandlerMethodAdapter implements BeanFactoryAware,
InitializingBean {
@@ -163,126 +149,169 @@ public class RequestMappingHandlerAdapter extends AbstractHandlerMethodAdapter i
private final Map, ModelFactory> modelFactoryCache = new ConcurrentHashMap, ModelFactory>();
/**
- * Create a {@link RequestMappingHandlerAdapter} instance.
+ * Default constructor.
*/
public RequestMappingHandlerAdapter() {
StringHttpMessageConverter stringHttpMessageConverter = new StringHttpMessageConverter();
stringHttpMessageConverter.setWriteAcceptCharset(false); // See SPR-7316
-
- messageConverters = new ArrayList>();
- messageConverters.add(new ByteArrayHttpMessageConverter());
- messageConverters.add(stringHttpMessageConverter);
- messageConverters.add(new SourceHttpMessageConverter());
- messageConverters.add(new XmlAwareFormHttpMessageConverter());
+
+ this.messageConverters = new ArrayList>();
+ this.messageConverters.add(new ByteArrayHttpMessageConverter());
+ this.messageConverters.add(stringHttpMessageConverter);
+ this.messageConverters.add(new SourceHttpMessageConverter());
+ this.messageConverters.add(new XmlAwareFormHttpMessageConverter());
}
/**
- * Set one or more custom argument resolvers to use with {@link RequestMapping}, {@link ModelAttribute}, and
- * {@link InitBinder} methods.
- *
Generally custom argument resolvers are invoked first. However this excludes
- * default argument resolvers that rely on the presence of annotations (e.g. {@code @RequestParameter},
- * {@code @PathVariable}, etc.) Those resolvers can only be customized via {@link #setArgumentResolvers(List)}
+ * Provide resolvers for custom argument types. Custom resolvers are ordered
+ * after built-in ones. To override the built-in support for argument
+ * resolution use {@link #setArgumentResolvers} instead.
*/
public void setCustomArgumentResolvers(List argumentResolvers) {
this.customArgumentResolvers = argumentResolvers;
}
-
+
/**
- * 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
+ * Return the custom argument resolvers, or {@code null}.
+ */
+ public List getCustomArgumentResolvers() {
+ return this.customArgumentResolvers;
+ }
+
+ /**
+ * Configure the complete list of supported argument types thus overriding
+ * the resolvers that would otherwise be configured by default.
*/
public void setArgumentResolvers(List argumentResolvers) {
- if (argumentResolvers != null) {
+ if (argumentResolvers == null) {
+ this.argumentResolvers = null;
+ }
+ else {
this.argumentResolvers = new HandlerMethodArgumentResolverComposite();
this.argumentResolvers.addResolvers(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
+ * Return the configured argument resolvers, or possibly {@code null} if
+ * not initialized yet via {@link #afterPropertiesSet()}.
+ */
+ public HandlerMethodArgumentResolverComposite getArgumentResolvers() {
+ return this.argumentResolvers;
+ }
+
+ /**
+ * Configure the supported argument types in {@code @InitBinder} methods.
*/
public void setInitBinderArgumentResolvers(List argumentResolvers) {
- if (argumentResolvers != null) {
+ if (argumentResolvers == null) {
+ this.initBinderArgumentResolvers = null;
+ }
+ else {
this.initBinderArgumentResolvers = new HandlerMethodArgumentResolverComposite();
this.initBinderArgumentResolvers.addResolvers(argumentResolvers);
}
}
/**
- * Set custom return value handlers to use to handle the return values of {@link RequestMapping} methods.
- *
Generally custom return value handlers are invoked first. However this excludes default return value
- * handlers that rely on the presence of annotations like {@code @ResponseBody}, {@code @ModelAttribute},
- * and others. Those handlers can only be customized via {@link #setReturnValueHandlers(List)}.
- * @param returnValueHandlers custom return value handlers for {@link RequestMapping} methods
+ * Return the argument resolvers for {@code @InitBinder} methods, or possibly
+ * {@code null} if not initialized yet via {@link #afterPropertiesSet()}.
+ */
+ public HandlerMethodArgumentResolverComposite getInitBinderArgumentResolvers() {
+ return this.initBinderArgumentResolvers;
+ }
+
+ /**
+ * Provide handlers for custom return value types. Custom handlers are
+ * ordered after built-in ones. To override the built-in support for
+ * return value handling use {@link #setReturnValueHandlers}.
*/
public void setCustomReturnValueHandlers(List returnValueHandlers) {
this.customReturnValueHandlers = 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
+ * Return the custom return value handlers, or {@code null}.
+ */
+ public List getCustomReturnValueHandlers() {
+ return this.customReturnValueHandlers;
+ }
+
+ /**
+ * Configure the complete list of supported return value types thus
+ * overriding handlers that would otherwise be configured by default.
*/
public void setReturnValueHandlers(List returnValueHandlers) {
- if (returnValueHandlers != null) {
+ if (returnValueHandlers == null) {
+ this.returnValueHandlers = null;
+ }
+ else {
this.returnValueHandlers = new HandlerMethodReturnValueHandlerComposite();
this.returnValueHandlers.addHandlers(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 end,
- * in {@link DefaultMethodReturnValueHandler}, after all standard {@link HandlerMethodReturnValueHandler}s.
- * This is because {@link ModelAndViewResolver}s do not have a method to indicate if they support a given
- * return type or not. For this reason it is recommended to use
- * {@link HandlerMethodReturnValueHandler} and {@link #setCustomReturnValueHandlers(List)} instead.
+ * Return the configured handlers, or possibly {@code null} if not
+ * initialized yet via {@link #afterPropertiesSet()}.
+ */
+ public HandlerMethodReturnValueHandlerComposite getReturnValueHandlers() {
+ return this.returnValueHandlers;
+ }
+
+ /**
+ * Provide custom {@link ModelAndViewResolver}s. This is available for
+ * backwards compatibility. However it is recommended to use
+ * {@link HandlerMethodReturnValueHandler}s instead.
*/
public void setModelAndViewResolvers(List modelAndViewResolvers) {
this.modelAndViewResolvers = modelAndViewResolvers;
}
/**
- * Set the message body converters to use.
- *
These converters are used to convert from and to HTTP requests and responses.
+ * Return the configured {@link ModelAndViewResolver}s, or {@code null}.
+ */
+ public List getModelAndViewResolvers() {
+ return modelAndViewResolvers;
+ }
+
+ /**
+ * Provide the converters to use in argument resolvers and return value
+ * handlers that support reading and/or writing to the body of the
+ * request and response.
*/
public void setMessageConverters(List> messageConverters) {
this.messageConverters = messageConverters;
}
/**
- * Return the message body converters that this adapter has been configured with.
+ * Return the configured message body converters.
*/
public List> getMessageConverters() {
return messageConverters;
}
/**
- * Set a WebBindingInitializer to apply configure every DataBinder instance this controller uses.
+ * Provide a WebBindingInitializer with "global" initialization to apply
+ * to every DataBinder instance.
*/
public void setWebBindingInitializer(WebBindingInitializer webBindingInitializer) {
this.webBindingInitializer = webBindingInitializer;
}
/**
- * Return the WebBindingInitializer which applies pre-configured configuration to {@link DataBinder} instances.
+ * Return the configured WebBindingInitializer, or {@code null}.
*/
public WebBindingInitializer getWebBindingInitializer() {
return webBindingInitializer;
}
/**
- * Specify the strategy to store session attributes with.
- *
Default is {@link org.springframework.web.bind.support.DefaultSessionAttributeStore},
- * storing session attributes in the HttpSession, using the same attribute name as in the model.
+ * Specify the strategy to store session attributes with. The default is
+ * {@link org.springframework.web.bind.support.DefaultSessionAttributeStore},
+ * storing session attributes in the HttpSession with the same attribute
+ * name as in the model.
*/
public void setSessionAttributeStore(SessionAttributeStore sessionAttributeStore) {
this.sessionAttributeStore = sessionAttributeStore;
@@ -291,9 +320,9 @@ public class RequestMappingHandlerAdapter extends AbstractHandlerMethodAdapter i
/**
* Cache content produced by @SessionAttributes annotated handlers
* for the given number of seconds. Default is 0, preventing caching completely.
- *
In contrast to the "cacheSeconds" property which will apply to all general handlers
- * (but not to @SessionAttributes annotated handlers), this setting will
- * apply to @SessionAttributes annotated handlers only.
+ *
In contrast to the "cacheSeconds" property which will apply to all general
+ * handlers (but not to @SessionAttributes annotated handlers),
+ * this setting will apply to @SessionAttributes handlers only.
* @see #setCacheSeconds
* @see org.springframework.web.bind.annotation.SessionAttributes
*/
@@ -324,9 +353,9 @@ public class RequestMappingHandlerAdapter extends AbstractHandlerMethodAdapter i
}
/**
- * Set the ParameterNameDiscoverer to use for resolving method parameter names if needed
- * (e.g. for default attribute names).
- *
Default is a {@link org.springframework.core.LocalVariableTableParameterNameDiscoverer}.
+ * Set the ParameterNameDiscoverer to use for resolving method parameter
+ * names if needed (e.g. for default attribute names). Default is a
+ * {@link org.springframework.core.LocalVariableTableParameterNameDiscoverer}.
*/
public void setParameterNameDiscoverer(ParameterNameDiscoverer parameterNameDiscoverer) {
this.parameterNameDiscoverer = parameterNameDiscoverer;
@@ -349,101 +378,144 @@ public class RequestMappingHandlerAdapter extends AbstractHandlerMethodAdapter i
this.ignoreDefaultModelOnRedirect = ignoreDefaultModelOnRedirect;
}
+ /**
+ * {@inheritDoc}
+ *
A {@link ConfigurableBeanFactory} is expected for resolving
+ * expressions in method argument default values.
+ */
public void setBeanFactory(BeanFactory beanFactory) {
if (beanFactory instanceof ConfigurableBeanFactory) {
this.beanFactory = (ConfigurableBeanFactory) beanFactory;
}
}
+ /**
+ * Return the owning factory of this bean instance, or {@code null}.
+ */
+ protected ConfigurableBeanFactory getBeanFactory() {
+ return this.beanFactory;
+ }
+
public void afterPropertiesSet() {
- initArgumentResolvers();
- initReturnValueHandlers();
- initInitBinderArgumentResolvers();
+ if (this.argumentResolvers == null) {
+ List resolvers = getDefaultArgumentResolvers();
+ this.argumentResolvers = new HandlerMethodArgumentResolverComposite().addResolvers(resolvers);
+ }
+ if (this.initBinderArgumentResolvers == null) {
+ List resolvers = getDefaultInitBinderArgumentResolvers();
+ this.initBinderArgumentResolvers = new HandlerMethodArgumentResolverComposite().addResolvers(resolvers);
+ }
+ if (this.returnValueHandlers == null) {
+ List handlers = getDefaultReturnValueHandlers();
+ this.returnValueHandlers = new HandlerMethodReturnValueHandlerComposite().addHandlers(handlers);
+ }
}
- private void initArgumentResolvers() {
- if (argumentResolvers != null) {
- return;
+ /**
+ * Return the list of argument resolvers to use including built-in resolvers
+ * and custom resolvers provided via {@link #setCustomArgumentResolvers}.
+ */
+ protected List getDefaultArgumentResolvers() {
+ List resolvers = new ArrayList();
+
+ // Annotation-based argument resolution
+ resolvers.add(new RequestParamMethodArgumentResolver(getBeanFactory(), false));
+ resolvers.add(new RequestParamMapMethodArgumentResolver());
+ resolvers.add(new PathVariableMethodArgumentResolver());
+ resolvers.add(new ServletModelAttributeMethodProcessor(false));
+ resolvers.add(new RequestResponseBodyMethodProcessor(getMessageConverters()));
+ resolvers.add(new RequestPartMethodArgumentResolver(getMessageConverters()));
+ resolvers.add(new RequestHeaderMethodArgumentResolver(getBeanFactory()));
+ resolvers.add(new RequestHeaderMapMethodArgumentResolver());
+ resolvers.add(new ServletCookieValueMethodArgumentResolver(getBeanFactory()));
+ resolvers.add(new ExpressionValueMethodArgumentResolver(getBeanFactory()));
+
+ // Type-based argument resolution
+ resolvers.add(new ServletRequestMethodArgumentResolver());
+ resolvers.add(new ServletResponseMethodArgumentResolver());
+ resolvers.add(new HttpEntityMethodProcessor(getMessageConverters()));
+ resolvers.add(new RedirectAttributesMethodArgumentResolver());
+ resolvers.add(new ModelMethodProcessor());
+ resolvers.add(new MapMethodProcessor());
+ resolvers.add(new ErrorsMethodArgumentResolver());
+ resolvers.add(new SessionStatusMethodArgumentResolver());
+
+ // Custom arguments
+ if (getCustomArgumentResolvers() != null) {
+ resolvers.addAll(getCustomArgumentResolvers());
}
- argumentResolvers = new HandlerMethodArgumentResolverComposite();
+ // Catch-all
+ resolvers.add(new RequestParamMethodArgumentResolver(getBeanFactory(), true));
+ resolvers.add(new ServletModelAttributeMethodProcessor(true));
- // Annotation-based resolvers
- argumentResolvers.addResolver(new RequestParamMethodArgumentResolver(beanFactory, false));
- argumentResolvers.addResolver(new RequestParamMapMethodArgumentResolver());
- argumentResolvers.addResolver(new PathVariableMethodArgumentResolver());
- argumentResolvers.addResolver(new ServletModelAttributeMethodProcessor(false));
- argumentResolvers.addResolver(new RequestResponseBodyMethodProcessor(messageConverters));
- argumentResolvers.addResolver(new RequestPartMethodArgumentResolver(messageConverters));
- argumentResolvers.addResolver(new RequestHeaderMethodArgumentResolver(beanFactory));
- argumentResolvers.addResolver(new RequestHeaderMapMethodArgumentResolver());
- argumentResolvers.addResolver(new ServletCookieValueMethodArgumentResolver(beanFactory));
- argumentResolvers.addResolver(new ExpressionValueMethodArgumentResolver(beanFactory));
-
- // Custom resolvers
- argumentResolvers.addResolvers(customArgumentResolvers);
-
- // Type-based resolvers
- argumentResolvers.addResolver(new ServletRequestMethodArgumentResolver());
- argumentResolvers.addResolver(new ServletResponseMethodArgumentResolver());
- argumentResolvers.addResolver(new HttpEntityMethodProcessor(messageConverters));
- argumentResolvers.addResolver(new RedirectAttributesMethodArgumentResolver());
- argumentResolvers.addResolver(new ModelMethodProcessor());
- argumentResolvers.addResolver(new ErrorsMethodArgumentResolver());
-
- // Default-mode resolution
- argumentResolvers.addResolver(new RequestParamMethodArgumentResolver(beanFactory, true));
- argumentResolvers.addResolver(new ServletModelAttributeMethodProcessor(true));
+ return resolvers;
}
- private void initInitBinderArgumentResolvers() {
- if (initBinderArgumentResolvers != null) {
- return;
+ /**
+ * Return the list of argument resolvers to use for {@code @InitBinder}
+ * methods including built-in and custom resolvers.
+ */
+ protected List getDefaultInitBinderArgumentResolvers() {
+ List resolvers = new ArrayList();
+
+ // Annotation-based argument resolution
+ resolvers.add(new RequestParamMethodArgumentResolver(getBeanFactory(), false));
+ resolvers.add(new RequestParamMapMethodArgumentResolver());
+ resolvers.add(new PathVariableMethodArgumentResolver());
+ resolvers.add(new ExpressionValueMethodArgumentResolver(getBeanFactory()));
+
+ // Type-based argument resolution
+ resolvers.add(new ServletRequestMethodArgumentResolver());
+ resolvers.add(new ServletResponseMethodArgumentResolver());
+
+ // Custom arguments
+ if (getCustomArgumentResolvers() != null) {
+ resolvers.addAll(getCustomArgumentResolvers());
}
- initBinderArgumentResolvers = new HandlerMethodArgumentResolverComposite();
-
- // Annotation-based resolvers
- initBinderArgumentResolvers.addResolver(new RequestParamMethodArgumentResolver(beanFactory, false));
- initBinderArgumentResolvers.addResolver(new RequestParamMapMethodArgumentResolver());
- initBinderArgumentResolvers.addResolver(new PathVariableMethodArgumentResolver());
- initBinderArgumentResolvers.addResolver(new ExpressionValueMethodArgumentResolver(beanFactory));
-
- // Custom resolvers
- initBinderArgumentResolvers.addResolvers(customArgumentResolvers);
-
- // Type-based resolvers
- initBinderArgumentResolvers.addResolver(new ServletRequestMethodArgumentResolver());
- initBinderArgumentResolvers.addResolver(new ServletResponseMethodArgumentResolver());
+ // Catch-all
+ resolvers.add(new RequestParamMethodArgumentResolver(getBeanFactory(), true));
- // Default-mode resolution
- initBinderArgumentResolvers.addResolver(new RequestParamMethodArgumentResolver(beanFactory, true));
+ return resolvers;
}
-
- private void initReturnValueHandlers() {
- if (returnValueHandlers != null) {
- return;
+
+ /**
+ * Return the list of return value handlers to use including built-in and
+ * custom handlers provided via {@link #setReturnValueHandlers}.
+ */
+ protected List getDefaultReturnValueHandlers() {
+ List handlers = new ArrayList();
+
+ // Single-purpose return value types
+ handlers.add(new ModelAndViewMethodReturnValueHandler());
+ handlers.add(new ModelMethodProcessor());
+ handlers.add(new ViewMethodReturnValueHandler());
+ handlers.add(new HttpEntityMethodProcessor(getMessageConverters()));
+
+ // Annotation-based return value types
+ handlers.add(new ModelAttributeMethodProcessor(false));
+ handlers.add(new RequestResponseBodyMethodProcessor(getMessageConverters()));
+
+ // Multi-purpose return value types
+ handlers.add(new ViewNameMethodReturnValueHandler());
+ handlers.add(new MapMethodProcessor());
+
+ // Custom return value types
+ if (getCustomReturnValueHandlers() != null) {
+ handlers.addAll(getCustomReturnValueHandlers());
}
- returnValueHandlers = new HandlerMethodReturnValueHandlerComposite();
+ // Catch-all
+ handlers.add(new DefaultMethodReturnValueHandler(getModelAndViewResolvers()));
- // Annotation-based handlers
- returnValueHandlers.addHandler(new RequestResponseBodyMethodProcessor(messageConverters));
- returnValueHandlers.addHandler(new ModelAttributeMethodProcessor(false));
-
- // Custom return value handlers
- returnValueHandlers.addHandlers(customReturnValueHandlers);
-
- // Type-based handlers
- returnValueHandlers.addHandler(new ModelAndViewMethodReturnValueHandler());
- returnValueHandlers.addHandler(new ModelMethodProcessor());
- returnValueHandlers.addHandler(new ViewMethodReturnValueHandler());
- returnValueHandlers.addHandler(new HttpEntityMethodProcessor(messageConverters));
-
- // Default handler
- returnValueHandlers.addHandler(new DefaultMethodReturnValueHandler(modelAndViewResolvers));
+ return handlers;
}
+ /**
+ * Return {@code true} if all arguments and the return value of the given
+ * HandlerMethod are supported by the configured resolvers and handlers.
+ */
@Override
protected boolean supportsInternal(HandlerMethod handlerMethod) {
return supportsMethodParameters(handlerMethod.getMethodParameters()) &&
@@ -465,11 +537,10 @@ public class RequestMappingHandlerAdapter extends AbstractHandlerMethodAdapter i
}
/**
- * {@inheritDoc}
- *
This implementation always returns -1 since {@link HandlerMethod} does not implement {@link LastModified}.
- * Instead an @{@link RequestMapping} method, calculate the lastModified value, and call
- * {@link WebRequest#checkNotModified(long)}, and return {@code null} if that returns {@code true}.
- * @see WebRequest#checkNotModified(long)
+ * This implementation always returns -1. An {@code @RequestMapping}
+ * method can calculate the lastModified value, call
+ * {@link WebRequest#checkNotModified(long)}, and return {@code null}
+ * if the result of that call is {@code true}.
*/
@Override
protected long getLastModifiedInternal(HttpServletRequest request, HandlerMethod handlerMethod) {
@@ -532,18 +603,16 @@ public class RequestMappingHandlerAdapter extends AbstractHandlerMethodAdapter i
ServletWebRequest webRequest = new ServletWebRequest(request, response);
WebDataBinderFactory binderFactory = getDataBinderFactory(handlerMethod);
- ServletInvocableHandlerMethod requestMappingMethod = createRequestMappingMethod(handlerMethod, binderFactory);
ModelFactory modelFactory = getModelFactory(handlerMethod, binderFactory);
+ ServletInvocableHandlerMethod requestMappingMethod = createRequestMappingMethod(handlerMethod, binderFactory);
ModelAndViewContainer mavContainer = new ModelAndViewContainer();
mavContainer.addAllAttributes(RequestContextUtils.getInputFlashMap(request));
modelFactory.initModel(webRequest, mavContainer, requestMappingMethod);
mavContainer.setIgnoreDefaultModelOnRedirect(this.ignoreDefaultModelOnRedirect);
- SessionStatus sessionStatus = new SimpleSessionStatus();
-
- requestMappingMethod.invokeAndHandle(webRequest, mavContainer, sessionStatus);
- modelFactory.updateModel(webRequest, mavContainer, sessionStatus);
+ requestMappingMethod.invokeAndHandle(webRequest, mavContainer);
+ modelFactory.updateModel(webRequest, mavContainer);
if (mavContainer.isRequestHandled()) {
return null;
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 fb8a9d7e6f..fca99efe26 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
@@ -19,7 +19,6 @@ package org.springframework.web.servlet.mvc.method.annotation.support;
import java.io.IOException;
import java.lang.reflect.Array;
import java.lang.reflect.GenericArrayType;
-import java.lang.reflect.Method;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.List;
@@ -39,8 +38,13 @@ import org.springframework.web.context.request.NativeWebRequest;
import org.springframework.web.method.support.ModelAndViewContainer;
/**
- * Resolves {@link HttpEntity} method argument values.
- * Handles {@link HttpEntity} and {@link ResponseEntity} return values.
+ * Resolves {@link HttpEntity} method argument values and also handles
+ * both {@link HttpEntity} and {@link ResponseEntity} return values.
+ *
+ *
An {@link HttpEntity} return type has a set purpose. Therefore this
+ * handler should be configured ahead of handlers that support any return
+ * value type annotated with {@code @ModelAttribute} or {@code @ResponseBody}
+ * to ensure they don't take over.
*
* @author Arjen Poutsma
* @author Rossen Stoyanchev
diff --git a/org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/mvc/method/annotation/support/ModelAndViewMethodReturnValueHandler.java b/org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/mvc/method/annotation/support/ModelAndViewMethodReturnValueHandler.java
index f4ff0727e0..771a2c9ec8 100644
--- a/org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/mvc/method/annotation/support/ModelAndViewMethodReturnValueHandler.java
+++ b/org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/mvc/method/annotation/support/ModelAndViewMethodReturnValueHandler.java
@@ -23,9 +23,17 @@ import org.springframework.web.method.support.ModelAndViewContainer;
import org.springframework.web.servlet.ModelAndView;
/**
- * Handles return values of type {@link ModelAndView} transferring their content to the {@link ModelAndViewContainer}.
- * If the return value is {@code null}, the {@link ModelAndViewContainer#setRequestHandled(boolean)} flag is set to
- * {@code false} to indicate view resolution is not needed.
+ * Handles return values of type {@link ModelAndView} copying view and model
+ * information to the {@link ModelAndViewContainer}.
+ *
+ *
If the return value is {@code null}, the
+ * {@link ModelAndViewContainer#setRequestHandled(boolean)} flag is set to
+ * {@code false} to indicate the request was handled directly.
+ *
+ *
A {@link ModelAndView} return type has a set purpose. Therefore this
+ * handler should be configured ahead of handlers that support any return
+ * value type annotated with {@code @ModelAttribute} or {@code @ResponseBody}
+ * to ensure they don't take over.
*
* @author Rossen Stoyanchev
* @since 3.1
diff --git a/org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/mvc/method/annotation/support/ViewMethodReturnValueHandler.java b/org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/mvc/method/annotation/support/ViewMethodReturnValueHandler.java
index 4052952e6d..e90cd3a20d 100644
--- a/org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/mvc/method/annotation/support/ViewMethodReturnValueHandler.java
+++ b/org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/mvc/method/annotation/support/ViewMethodReturnValueHandler.java
@@ -17,8 +17,6 @@
package org.springframework.web.servlet.mvc.method.annotation.support;
import org.springframework.core.MethodParameter;
-import org.springframework.web.bind.annotation.ModelAttribute;
-import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.context.request.NativeWebRequest;
import org.springframework.web.method.support.HandlerMethodReturnValueHandler;
import org.springframework.web.method.support.ModelAndViewContainer;
@@ -27,27 +25,23 @@ import org.springframework.web.servlet.SmartView;
import org.springframework.web.servlet.View;
/**
- * Handles return values that are of type {@code void}, {@code String} (i.e.
- * logical view name), or {@link View}.
+ * Handles return values that are of type {@link View}.
*
- *
A {@code null} return value, either due to a void return type or as the
- * actual value returned from a method is left unhandled, leaving it to the
- * configured {@link RequestToViewNameTranslator} to resolve the request to
- * an actual view name.
- *
- *
Since a {@link String} return value may be handled in combination with
- * method annotations such as @{@link ModelAttribute} or @{@link ResponseBody},
- * this handler should be ordered after return value handlers that support
- * method annotations.
+ *
A {@code null} return value is left as-is leaving it to the configured
+ * {@link RequestToViewNameTranslator} to select a view name by convention.
*
+ *
A {@link View} return type has a set purpose. Therefore this handler
+ * should be configured ahead of handlers that support any return value type
+ * annotated with {@code @ModelAttribute} or {@code @ResponseBody} to ensure
+ * they don't take over.
+ *
* @author Rossen Stoyanchev
* @since 3.1
*/
public class ViewMethodReturnValueHandler implements HandlerMethodReturnValueHandler {
public boolean supportsReturnType(MethodParameter returnType) {
- Class> type = returnType.getParameterType();
- return (void.class.equals(type) || String.class.equals(type) || View.class.isAssignableFrom(type));
+ return View.class.isAssignableFrom(returnType.getParameterType());
}
public void handleReturnValue(Object returnValue,
@@ -57,50 +51,20 @@ public class ViewMethodReturnValueHandler implements HandlerMethodReturnValueHan
if (returnValue == null) {
return;
}
- if (returnValue instanceof String) {
- String viewName = (String) returnValue;
- mavContainer.setViewName(viewName);
- if (isRedirectViewName(viewName)) {
- mavContainer.setUseRedirectModel(true);
- }
- }
else if (returnValue instanceof View){
View view = (View) returnValue;
mavContainer.setView(view);
- if (isRedirectView(view)) {
- mavContainer.setUseRedirectModel(true);
+ if (view instanceof SmartView) {
+ if (((SmartView) view).isRedirectView()) {
+ mavContainer.setRedirectModelScenario(true);
+ }
}
}
else {
// should not happen
- throw new UnsupportedOperationException("Unknown return type: " +
+ throw new UnsupportedOperationException("Unexpected return type: " +
returnType.getParameterType().getName() + " in method: " + returnType.getMethod());
}
}
- /**
- * Whether the given view name is a redirect view reference.
- * @param viewName the view name to check, never {@code null}
- * @return "true" if the given view name is recognized as a redirect view
- * reference; "false" otherwise.
- */
- protected boolean isRedirectViewName(String viewName) {
- return viewName.startsWith("redirect:");
- }
-
- /**
- * Whether the given View instance is a redirect view.
- * @param view a view instance, never {@code null}
- * @return "true" if the given view is recognized as a redirect View;
- * "false" otherwise.
- */
- protected boolean isRedirectView(View view) {
- if (view instanceof SmartView) {
- return ((SmartView) view).isRedirectView();
- }
- else {
- return false;
- }
- }
-
}
diff --git a/org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/mvc/method/annotation/support/ViewNameMethodReturnValueHandler.java b/org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/mvc/method/annotation/support/ViewNameMethodReturnValueHandler.java
new file mode 100644
index 0000000000..8b983d688d
--- /dev/null
+++ b/org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/mvc/method/annotation/support/ViewNameMethodReturnValueHandler.java
@@ -0,0 +1,79 @@
+/*
+ * Copyright 2002-2011 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.springframework.web.servlet.mvc.method.annotation.support;
+
+import org.springframework.core.MethodParameter;
+import org.springframework.web.context.request.NativeWebRequest;
+import org.springframework.web.method.support.HandlerMethodReturnValueHandler;
+import org.springframework.web.method.support.ModelAndViewContainer;
+import org.springframework.web.servlet.RequestToViewNameTranslator;
+
+/**
+ * Handles return values of types {@code void} and {@code String} interpreting
+ * them as view name reference.
+ *
+ *
A {@code null} return value, either due to a {@code void} return type or
+ * as the actual return value is left as-is allowing the configured
+ * {@link RequestToViewNameTranslator} to select a view name by convention.
+ *
+ *
A String return value can be interpreted in more than one ways depending
+ * on the presence of annotations like {@code @ModelAttribute} or
+ * {@code @ResponseBody}. Therefore this handler should be configured after
+ * the handlers that support these annotations.
+ *
+ * @author Rossen Stoyanchev
+ * @since 3.1
+ */
+public class ViewNameMethodReturnValueHandler implements HandlerMethodReturnValueHandler {
+
+ public boolean supportsReturnType(MethodParameter returnType) {
+ Class> paramType = returnType.getParameterType();
+ return (void.class.equals(paramType) || String.class.equals(paramType));
+ }
+
+ public void handleReturnValue(Object returnValue,
+ MethodParameter returnType,
+ ModelAndViewContainer mavContainer,
+ NativeWebRequest webRequest) throws Exception {
+ if (returnValue == null) {
+ return;
+ }
+ else if (returnValue instanceof String) {
+ String viewName = (String) returnValue;
+ mavContainer.setViewName(viewName);
+ if (isRedirectViewName(viewName)) {
+ mavContainer.setRedirectModelScenario(true);
+ }
+ }
+ else {
+ // should not happen
+ throw new UnsupportedOperationException("Unexpected return type: " +
+ returnType.getParameterType().getName() + " in method: " + returnType.getMethod());
+ }
+ }
+
+ /**
+ * Whether the given view name is a redirect view reference.
+ * @param viewName the view name to check, never {@code null}
+ * @return "true" if the given view name is recognized as a redirect view
+ * reference; "false" otherwise.
+ */
+ protected boolean isRedirectViewName(String viewName) {
+ return viewName.startsWith("redirect:");
+ }
+
+}
diff --git a/org.springframework.web.servlet/src/main/resources/org/springframework/web/servlet/config/spring-mvc-3.1.xsd b/org.springframework.web.servlet/src/main/resources/org/springframework/web/servlet/config/spring-mvc-3.1.xsd
index 90b54c88a2..52a9ef429c 100644
--- a/org.springframework.web.servlet/src/main/resources/org/springframework/web/servlet/config/spring-mvc-3.1.xsd
+++ b/org.springframework.web.servlet/src/main/resources/org/springframework/web/servlet/config/spring-mvc-3.1.xsd
@@ -53,10 +53,9 @@
@@ -64,7 +63,7 @@
@@ -74,9 +73,9 @@
diff --git a/org.springframework.web.servlet/src/test/java/org/springframework/web/servlet/mvc/method/annotation/RequestMappingHandlerAdapterIntegrationTests.java b/org.springframework.web.servlet/src/test/java/org/springframework/web/servlet/mvc/method/annotation/RequestMappingHandlerAdapterIntegrationTests.java
index 85c79335da..a239e23a74 100644
--- a/org.springframework.web.servlet/src/test/java/org/springframework/web/servlet/mvc/method/annotation/RequestMappingHandlerAdapterIntegrationTests.java
+++ b/org.springframework.web.servlet/src/test/java/org/springframework/web/servlet/mvc/method/annotation/RequestMappingHandlerAdapterIntegrationTests.java
@@ -17,6 +17,7 @@
package org.springframework.web.servlet.mvc.method.annotation;
import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertSame;
@@ -72,6 +73,7 @@ import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.web.bind.annotation.SessionAttributes;
import org.springframework.web.bind.support.ConfigurableWebBindingInitializer;
+import org.springframework.web.bind.support.SessionStatus;
import org.springframework.web.bind.support.WebArgumentResolver;
import org.springframework.web.context.request.NativeWebRequest;
import org.springframework.web.context.request.RequestContextHolder;
@@ -138,7 +140,7 @@ public class RequestMappingHandlerAdapterIntegrationTests {
}
@Test
- public void handleMvc() throws Exception {
+ public void handle() throws Exception {
Class>[] parameterTypes = new Class>[] { int.class, String.class, String.class, String.class, Map.class,
Date.class, Map.class, String.class, String.class, TestBean.class, Errors.class, TestBean.class,
@@ -160,15 +162,12 @@ public class RequestMappingHandlerAdapterIntegrationTests {
request.setContent("Hello World".getBytes("UTF-8"));
request.setUserPrincipal(new User());
request.setContextPath("/contextPath");
-
System.setProperty("systemHeader", "systemHeaderValue");
-
- /* Set up path variables as RequestMappingHandlerMapping would... */
Map uriTemplateVars = new HashMap();
uriTemplateVars.put("pathvar", "pathvarValue");
request.setAttribute(HandlerMapping.URI_TEMPLATE_VARIABLES_ATTRIBUTE, uriTemplateVars);
- HandlerMethod handlerMethod = handlerMethod("handleMvc", parameterTypes);
+ HandlerMethod handlerMethod = handlerMethod("handle", parameterTypes);
ModelAndView mav = handlerAdapter.handle(request, response, handlerMethod);
ModelMap model = mav.getModelMap();
@@ -259,6 +258,14 @@ public class RequestMappingHandlerAdapterIntegrationTests {
assertEquals("content", mav.getModelMap().get("requestPart"));
}
+ @Test
+ public void handleAndCompleteSession() throws Exception {
+ HandlerMethod handlerMethod = handlerMethod("handleAndCompleteSession", SessionStatus.class);
+ ModelAndView mav = handlerAdapter.handle(request, response, handlerMethod);
+
+ assertFalse(request.getSession().getAttributeNames().hasMoreElements());
+ }
+
private HandlerMethod handlerMethod(String methodName, Class>... paramTypes) throws Exception {
Method method = handler.getClass().getDeclaredMethod(methodName, paramTypes);
return new InvocableHandlerMethod(handler, method);
@@ -287,7 +294,7 @@ public class RequestMappingHandlerAdapterIntegrationTests {
model.addAttribute(new OtherUser());
}
- public String handleMvc(
+ public String handle(
@CookieValue("cookie") int cookie,
@PathVariable("pathvar") String pathvar,
@RequestHeader("header") String header,
@@ -336,6 +343,10 @@ public class RequestMappingHandlerAdapterIntegrationTests {
public void handleRequestPart(@RequestPart String requestPart, Model model) {
model.addAttribute("requestPart", requestPart);
}
+
+ public void handleAndCompleteSession(SessionStatus sessionStatus) {
+ sessionStatus.setComplete();
+ }
}
private static class StubValidator implements Validator {
diff --git a/org.springframework.web.servlet/src/test/java/org/springframework/web/servlet/mvc/method/annotation/RequestMappingHandlerAdapterTests.java b/org.springframework.web.servlet/src/test/java/org/springframework/web/servlet/mvc/method/annotation/RequestMappingHandlerAdapterTests.java
index 616e6de1b5..1b1b648f87 100644
--- a/org.springframework.web.servlet/src/test/java/org/springframework/web/servlet/mvc/method/annotation/RequestMappingHandlerAdapterTests.java
+++ b/org.springframework.web.servlet/src/test/java/org/springframework/web/servlet/mvc/method/annotation/RequestMappingHandlerAdapterTests.java
@@ -20,35 +20,27 @@ import static org.junit.Assert.assertEquals;
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.BeforeClass;
import org.junit.Test;
-import org.springframework.beans.DirectFieldAccessor;
-import org.springframework.core.MethodParameter;
import org.springframework.mock.web.MockHttpServletRequest;
import org.springframework.mock.web.MockHttpServletResponse;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.SessionAttributes;
-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.HandlerMethod;
import org.springframework.web.method.annotation.support.ModelMethodProcessor;
import org.springframework.web.method.support.HandlerMethodArgumentResolver;
-import org.springframework.web.method.support.HandlerMethodArgumentResolverComposite;
import org.springframework.web.method.support.HandlerMethodReturnValueHandler;
-import org.springframework.web.method.support.HandlerMethodReturnValueHandlerComposite;
import org.springframework.web.method.support.InvocableHandlerMethod;
-import org.springframework.web.method.support.ModelAndViewContainer;
import org.springframework.web.servlet.FlashMap;
import org.springframework.web.servlet.FlashMapManager;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.mvc.method.annotation.support.RedirectAttributesMethodArgumentResolver;
import org.springframework.web.servlet.mvc.method.annotation.support.ServletRequestMethodArgumentResolver;
-import org.springframework.web.servlet.mvc.method.annotation.support.ViewMethodReturnValueHandler;
+import org.springframework.web.servlet.mvc.method.annotation.support.ViewNameMethodReturnValueHandler;
/**
* Unit tests for {@link RequestMappingHandlerAdapter}.
@@ -61,12 +53,28 @@ import org.springframework.web.servlet.mvc.method.annotation.support.ViewMethodR
*/
public class RequestMappingHandlerAdapterTests {
+ private static int RESOLVER_COUNT;
+
+ private static int INIT_BINDER_RESOLVER_COUNT;
+
+ private static int HANDLER_COUNT;
+
private RequestMappingHandlerAdapter handlerAdapter;
private MockHttpServletRequest request;
private MockHttpServletResponse response;
+ @BeforeClass
+ public static void setupOnce() {
+ RequestMappingHandlerAdapter adapter = new RequestMappingHandlerAdapter();
+ adapter.afterPropertiesSet();
+
+ RESOLVER_COUNT = adapter.getArgumentResolvers().getResolvers().size();
+ INIT_BINDER_RESOLVER_COUNT = adapter.getInitBinderArgumentResolvers().getResolvers().size();
+ HANDLER_COUNT = adapter.getReturnValueHandlers().getHandlers().size();
+ }
+
@Before
public void setup() throws Exception {
this.handlerAdapter = new RequestMappingHandlerAdapter();
@@ -77,17 +85,17 @@ public class RequestMappingHandlerAdapterTests {
@Test
public void cacheControlWithoutSessionAttributes() throws Exception {
- SimpleHandler handler = new SimpleHandler();
+ HandlerMethod handlerMethod = handlerMethod(new SimpleController(), "handle");
handlerAdapter.afterPropertiesSet();
handlerAdapter.setCacheSeconds(100);
- handlerAdapter.handle(request, response, handlerMethod(handler, "handle"));
+ handlerAdapter.handle(request, response, handlerMethod);
assertTrue(response.getHeader("Cache-Control").toString().contains("max-age"));
}
@Test
public void cacheControlWithSessionAttributes() throws Exception {
- SessionAttributeHandler handler = new SessionAttributeHandler();
+ SessionAttributeController handler = new SessionAttributeController();
handlerAdapter.afterPropertiesSet();
handlerAdapter.setCacheSeconds(100);
handlerAdapter.handle(request, response, handlerMethod(handler, "handle"));
@@ -99,7 +107,7 @@ public class RequestMappingHandlerAdapterTests {
public void setAlwaysUseRedirectAttributes() throws Exception {
HandlerMethodArgumentResolver redirectAttributesResolver = new RedirectAttributesMethodArgumentResolver();
HandlerMethodArgumentResolver modelResolver = new ModelMethodProcessor();
- HandlerMethodReturnValueHandler viewHandler = new ViewMethodReturnValueHandler();
+ HandlerMethodReturnValueHandler viewHandler = new ViewNameMethodReturnValueHandler();
handlerAdapter.setArgumentResolvers(Arrays.asList(redirectAttributesResolver, modelResolver));
handlerAdapter.setReturnValueHandlers(Arrays.asList(viewHandler));
@@ -108,104 +116,57 @@ public class RequestMappingHandlerAdapterTests {
request.setAttribute(FlashMapManager.OUTPUT_FLASH_MAP_ATTRIBUTE, new FlashMap());
- HandlerMethod handlerMethod = handlerMethod(new RedirectAttributeHandler(), "handle", Model.class);
+ HandlerMethod handlerMethod = handlerMethod(new RedirectAttributeController(), "handle", Model.class);
ModelAndView mav = handlerAdapter.handle(request, response, handlerMethod);
assertTrue("Without RedirectAttributes arg, model should be empty", mav.getModel().isEmpty());
}
@Test
- @SuppressWarnings("unchecked")
- public void setArgumentResolvers() {
- List argumentResolvers = new ArrayList();
- argumentResolvers.add(new ServletRequestMethodArgumentResolver());
-
- handlerAdapter.setArgumentResolvers(argumentResolvers);
- handlerAdapter.afterPropertiesSet();
+ public void setCustomArgumentResolvers() throws Exception {
+ HandlerMethodArgumentResolver resolver = new ServletRequestMethodArgumentResolver();
+ this.handlerAdapter.setCustomArgumentResolvers(Arrays.asList(resolver));
+ this.handlerAdapter.afterPropertiesSet();
- HandlerMethodArgumentResolverComposite composite = (HandlerMethodArgumentResolverComposite)
- new DirectFieldAccessor(handlerAdapter).getPropertyValue("argumentResolvers");
-
- List actual = (List)
- new DirectFieldAccessor(composite).getPropertyValue("argumentResolvers");
-
- assertEquals(argumentResolvers, actual);
+ assertTrue(this.handlerAdapter.getArgumentResolvers().getResolvers().contains(resolver));
+ assertMethodProcessorCount(RESOLVER_COUNT + 1, INIT_BINDER_RESOLVER_COUNT + 1, HANDLER_COUNT);
}
@Test
- @SuppressWarnings("unchecked")
- public void setInitBinderArgumentResolvers() {
- List argumentResolvers = new ArrayList();
- argumentResolvers.add(new ServletRequestMethodArgumentResolver());
-
- handlerAdapter.setInitBinderArgumentResolvers(argumentResolvers);
- handlerAdapter.afterPropertiesSet();
-
- HandlerMethodArgumentResolverComposite composite = (HandlerMethodArgumentResolverComposite)
- new DirectFieldAccessor(handlerAdapter).getPropertyValue("initBinderArgumentResolvers");
+ public void setArgumentResolvers() throws Exception {
+ HandlerMethodArgumentResolver resolver = new ServletRequestMethodArgumentResolver();
+ this.handlerAdapter.setArgumentResolvers(Arrays.asList(resolver));
+ this.handlerAdapter.afterPropertiesSet();
- List actual = (List)
- new DirectFieldAccessor(composite).getPropertyValue("argumentResolvers");
-
- assertEquals(argumentResolvers, actual);
+ assertMethodProcessorCount(1, INIT_BINDER_RESOLVER_COUNT, HANDLER_COUNT);
}
@Test
- @SuppressWarnings("unchecked")
+ public void setInitBinderArgumentResolvers() throws Exception {
+ HandlerMethodArgumentResolver resolver = new ServletRequestMethodArgumentResolver();
+ handlerAdapter.setInitBinderArgumentResolvers(Arrays.asList(resolver));
+ handlerAdapter.afterPropertiesSet();
+
+ assertMethodProcessorCount(RESOLVER_COUNT, 1, HANDLER_COUNT);
+ }
+
+ @Test
+ public void setCustomReturnValueHandlers() {
+ HandlerMethodReturnValueHandler handler = new ViewNameMethodReturnValueHandler();
+ handlerAdapter.setCustomReturnValueHandlers(Arrays.asList(handler));
+ handlerAdapter.afterPropertiesSet();
+
+ assertTrue(this.handlerAdapter.getReturnValueHandlers().getHandlers().contains(handler));
+ assertMethodProcessorCount(RESOLVER_COUNT, INIT_BINDER_RESOLVER_COUNT, HANDLER_COUNT + 1);
+ }
+
+ @Test
public void setReturnValueHandlers() {
HandlerMethodReturnValueHandler handler = new ModelMethodProcessor();
- List handlers = Arrays.asList(handler);
-
- handlerAdapter.setReturnValueHandlers(handlers);
+ handlerAdapter.setReturnValueHandlers(Arrays.asList(handler));
handlerAdapter.afterPropertiesSet();
-
- HandlerMethodReturnValueHandlerComposite composite = (HandlerMethodReturnValueHandlerComposite)
- new DirectFieldAccessor(handlerAdapter).getPropertyValue("returnValueHandlers");
- List actual = (List)
- new DirectFieldAccessor(composite).getPropertyValue("returnValueHandlers");
-
- assertEquals(handlers, actual);
- }
-
- @Test
- @SuppressWarnings("unchecked")
- public void setCustomArgumentResolvers() {
- HandlerMethodArgumentResolver resolver = new TestHanderMethodArgumentResolver();
- handlerAdapter.setCustomArgumentResolvers(Arrays.asList(resolver));
- handlerAdapter.afterPropertiesSet();
-
- HandlerMethodArgumentResolverComposite composite = (HandlerMethodArgumentResolverComposite)
- new DirectFieldAccessor(handlerAdapter).getPropertyValue("argumentResolvers");
-
- List actual = (List)
- new DirectFieldAccessor(composite).getPropertyValue("argumentResolvers");
-
- assertTrue(actual.contains(resolver));
-
- composite = (HandlerMethodArgumentResolverComposite)
- new DirectFieldAccessor(handlerAdapter).getPropertyValue("initBinderArgumentResolvers");
-
- actual = (List)
- new DirectFieldAccessor(composite).getPropertyValue("argumentResolvers");
-
- assertTrue(actual.contains(resolver));
- }
-
- @Test
- @SuppressWarnings("unchecked")
- public void setCustomReturnValueHandlers() {
- TestHandlerMethodReturnValueHandler handler = new TestHandlerMethodReturnValueHandler();
- handlerAdapter.setCustomReturnValueHandlers(Arrays.asList(handler));
- handlerAdapter.afterPropertiesSet();
-
- HandlerMethodReturnValueHandlerComposite composite = (HandlerMethodReturnValueHandlerComposite)
- new DirectFieldAccessor(handlerAdapter).getPropertyValue("returnValueHandlers");
-
- List actual = (List)
- new DirectFieldAccessor(composite).getPropertyValue("returnValueHandlers");
-
- assertTrue(actual.contains(handler));
+ assertMethodProcessorCount(RESOLVER_COUNT, INIT_BINDER_RESOLVER_COUNT, 1);
}
private HandlerMethod handlerMethod(Object handler, String methodName, Class>... paramTypes) throws Exception {
@@ -213,46 +174,37 @@ public class RequestMappingHandlerAdapterTests {
return new InvocableHandlerMethod(handler, method);
}
- private final class TestHanderMethodArgumentResolver implements HandlerMethodArgumentResolver {
+
- public boolean supportsParameter(MethodParameter parameter) {
- return false;
- }
+ private void assertMethodProcessorCount(int resolverCount, int initBinderResolverCount, int handlerCount) {
+ assertEquals(resolverCount, this.handlerAdapter.getArgumentResolvers().getResolvers().size());
+ assertEquals(initBinderResolverCount, this.handlerAdapter.getInitBinderArgumentResolvers().getResolvers().size());
+ assertEquals(handlerCount, this.handlerAdapter.getReturnValueHandlers().getHandlers().size());
+ }
- public Object resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer,
- NativeWebRequest webRequest, WebDataBinderFactory binderFactory) throws Exception {
+ @SuppressWarnings("unused")
+ private static class SimpleController {
+
+ public String handle() {
return null;
}
}
- private final class TestHandlerMethodReturnValueHandler implements HandlerMethodReturnValueHandler{
-
- public boolean supportsReturnType(MethodParameter returnType) {
- return false;
- }
-
- public void handleReturnValue(Object returnValue, MethodParameter returnType,
- ModelAndViewContainer mavContainer, NativeWebRequest webRequest) throws Exception {
- }
- }
-
- static class SimpleHandler {
- public void handle() {
- }
- }
-
@SessionAttributes("attr1")
- static class SessionAttributeHandler {
+ private static class SessionAttributeController {
+
+ @SuppressWarnings("unused")
public void handle() {
}
}
- static class RedirectAttributeHandler {
+ @SuppressWarnings("unused")
+ private static class RedirectAttributeController {
+
public String handle(Model model) {
model.addAttribute("someAttr", "someAttrValue");
return "redirect:/path";
}
}
-
}
\ No newline at end of file
diff --git a/org.springframework.web.servlet/src/test/java/org/springframework/web/servlet/mvc/method/annotation/support/ViewMethodReturnValueHandlerTests.java b/org.springframework.web.servlet/src/test/java/org/springframework/web/servlet/mvc/method/annotation/support/ViewMethodReturnValueHandlerTests.java
index 6cfafd20ce..d49891708b 100644
--- a/org.springframework.web.servlet/src/test/java/org/springframework/web/servlet/mvc/method/annotation/support/ViewMethodReturnValueHandlerTests.java
+++ b/org.springframework.web.servlet/src/test/java/org/springframework/web/servlet/mvc/method/annotation/support/ViewMethodReturnValueHandlerTests.java
@@ -16,7 +16,6 @@
package org.springframework.web.servlet.mvc.method.annotation.support;
-import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertSame;
import static org.junit.Assert.assertTrue;
@@ -35,7 +34,7 @@ import org.springframework.web.servlet.view.InternalResourceView;
import org.springframework.web.servlet.view.RedirectView;
/**
- * Test fixture with {@link DefaultMethodReturnValueHandler}.
+ * Test fixture with {@link ViewMethodReturnValueHandler}.
*
* @author Rossen Stoyanchev
*/
@@ -57,7 +56,6 @@ public class ViewMethodReturnValueHandlerTests {
@Test
public void supportsReturnType() throws Exception {
assertTrue(this.handler.supportsReturnType(createReturnValueParam("view")));
- assertTrue(this.handler.supportsReturnType(createReturnValueParam("viewName")));
}
@Test
@@ -79,25 +77,6 @@ public class ViewMethodReturnValueHandlerTests {
assertSame(redirectView, this.mavContainer.getView());
assertSame("Should have switched to the RedirectModel", redirectModel, this.mavContainer.getModel());
}
-
- @Test
- public void returnViewName() throws Exception {
- MethodParameter param = createReturnValueParam("viewName");
- this.handler.handleReturnValue("testView", param, this.mavContainer, this.webRequest);
-
- assertEquals("testView", this.mavContainer.getViewName());
- }
-
- @Test
- public void returnViewNameRedirect() throws Exception {
- ModelMap redirectModel = new RedirectAttributesModelMap();
- this.mavContainer.setRedirectModel(redirectModel);
- MethodParameter param = createReturnValueParam("viewName");
- this.handler.handleReturnValue("redirect:testView", param, this.mavContainer, this.webRequest);
-
- assertEquals("redirect:testView", this.mavContainer.getViewName());
- assertSame("Should have switched to the RedirectModel", redirectModel, this.mavContainer.getModel());
- }
private MethodParameter createReturnValueParam(String methodName) throws Exception {
Method method = getClass().getDeclaredMethod(methodName);
@@ -108,8 +87,4 @@ public class ViewMethodReturnValueHandlerTests {
return null;
}
- String viewName() {
- return null;
- }
-
}
\ No newline at end of file
diff --git a/org.springframework.web.servlet/src/test/java/org/springframework/web/servlet/mvc/method/annotation/support/ViewNameMethodReturnValueHandlerTests.java b/org.springframework.web.servlet/src/test/java/org/springframework/web/servlet/mvc/method/annotation/support/ViewNameMethodReturnValueHandlerTests.java
new file mode 100644
index 0000000000..f4b7d64288
--- /dev/null
+++ b/org.springframework.web.servlet/src/test/java/org/springframework/web/servlet/mvc/method/annotation/support/ViewNameMethodReturnValueHandlerTests.java
@@ -0,0 +1,87 @@
+/*
+ * Copyright 2002-2011 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.springframework.web.servlet.mvc.method.annotation.support;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertSame;
+import static org.junit.Assert.assertTrue;
+
+import java.lang.reflect.Method;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.springframework.core.MethodParameter;
+import org.springframework.mock.web.MockHttpServletRequest;
+import org.springframework.ui.ModelMap;
+import org.springframework.web.context.request.ServletWebRequest;
+import org.springframework.web.method.support.ModelAndViewContainer;
+import org.springframework.web.servlet.mvc.support.RedirectAttributesModelMap;
+
+/**
+ * Test fixture with {@link ViewNameMethodReturnValueHandler}.
+ *
+ * @author Rossen Stoyanchev
+ */
+public class ViewNameMethodReturnValueHandlerTests {
+
+ private ViewNameMethodReturnValueHandler handler;
+
+ private ModelAndViewContainer mavContainer;
+
+ private ServletWebRequest webRequest;
+
+ @Before
+ public void setUp() {
+ this.handler = new ViewNameMethodReturnValueHandler();
+ this.mavContainer = new ModelAndViewContainer();
+ this.webRequest = new ServletWebRequest(new MockHttpServletRequest());
+ }
+
+ @Test
+ public void supportsReturnType() throws Exception {
+ assertTrue(this.handler.supportsReturnType(createReturnValueParam("viewName")));
+ }
+
+ @Test
+ public void returnViewName() throws Exception {
+ MethodParameter param = createReturnValueParam("viewName");
+ this.handler.handleReturnValue("testView", param, this.mavContainer, this.webRequest);
+
+ assertEquals("testView", this.mavContainer.getViewName());
+ }
+
+ @Test
+ public void returnViewNameRedirect() throws Exception {
+ ModelMap redirectModel = new RedirectAttributesModelMap();
+ this.mavContainer.setRedirectModel(redirectModel);
+ MethodParameter param = createReturnValueParam("viewName");
+ this.handler.handleReturnValue("redirect:testView", param, this.mavContainer, this.webRequest);
+
+ assertEquals("redirect:testView", this.mavContainer.getViewName());
+ assertSame("Should have switched to the RedirectModel", redirectModel, this.mavContainer.getModel());
+ }
+
+ private MethodParameter createReturnValueParam(String methodName) throws Exception {
+ Method method = getClass().getDeclaredMethod(methodName);
+ return new MethodParameter(method, -1);
+ }
+
+ String viewName() {
+ return null;
+ }
+
+}
\ No newline at end of file
diff --git a/org.springframework.web/src/main/java/org/springframework/web/method/annotation/ModelFactory.java b/org.springframework.web/src/main/java/org/springframework/web/method/annotation/ModelFactory.java
index 24ab6e84a3..d1985e684c 100644
--- a/org.springframework.web/src/main/java/org/springframework/web/method/annotation/ModelFactory.java
+++ b/org.springframework.web/src/main/java/org/springframework/web/method/annotation/ModelFactory.java
@@ -198,13 +198,11 @@ public final class ModelFactory {
* promotes model attributes to the session, and adds {@link BindingResult} attributes where missing.
* @param request the current request
* @param mavContainer the {@link ModelAndViewContainer} for the current request
- * @param sessionStatus the session status for the current request
* @throws Exception if the process of creating {@link BindingResult} attributes causes an error
*/
- public void updateModel(NativeWebRequest request, ModelAndViewContainer mavContainer, SessionStatus sessionStatus)
- throws Exception {
+ public void updateModel(NativeWebRequest request, ModelAndViewContainer mavContainer) throws Exception {
- if (sessionStatus.isComplete()){
+ if (mavContainer.getSessionStatus().isComplete()){
this.sessionAttributesHandler.cleanupAttributes(request);
}
else {
diff --git a/org.springframework.web/src/main/java/org/springframework/web/method/annotation/support/AbstractNamedValueMethodArgumentResolver.java b/org.springframework.web/src/main/java/org/springframework/web/method/annotation/support/AbstractNamedValueMethodArgumentResolver.java
index a2ca492ef2..37d2599377 100644
--- a/org.springframework.web/src/main/java/org/springframework/web/method/annotation/support/AbstractNamedValueMethodArgumentResolver.java
+++ b/org.springframework.web/src/main/java/org/springframework/web/method/annotation/support/AbstractNamedValueMethodArgumentResolver.java
@@ -55,7 +55,7 @@ import org.springframework.web.method.support.ModelAndViewContainer;
*/
public abstract class AbstractNamedValueMethodArgumentResolver implements HandlerMethodArgumentResolver {
- private final ConfigurableBeanFactory beanFactory;
+ private final ConfigurableBeanFactory configurableBeanFactory;
private final BeanExpressionContext expressionContext;
@@ -67,7 +67,7 @@ public abstract class AbstractNamedValueMethodArgumentResolver implements Handle
* in default values, or {@code null} if default values are not expected to contain expressions
*/
public AbstractNamedValueMethodArgumentResolver(ConfigurableBeanFactory beanFactory) {
- this.beanFactory = beanFactory;
+ this.configurableBeanFactory = beanFactory;
this.expressionContext = (beanFactory != null) ? new BeanExpressionContext(beanFactory, new RequestScope()) : null;
}
@@ -105,11 +105,11 @@ public abstract class AbstractNamedValueMethodArgumentResolver implements Handle
* Obtain the named value for the given method parameter.
*/
private NamedValueInfo getNamedValueInfo(MethodParameter parameter) {
- NamedValueInfo namedValueInfo = namedValueInfoCache.get(parameter);
+ NamedValueInfo namedValueInfo = this.namedValueInfoCache.get(parameter);
if (namedValueInfo == null) {
namedValueInfo = createNamedValueInfo(parameter);
namedValueInfo = updateNamedValueInfo(parameter, namedValueInfo);
- namedValueInfoCache.put(parameter, namedValueInfo);
+ this.namedValueInfoCache.put(parameter, namedValueInfo);
}
return namedValueInfo;
}
@@ -153,15 +153,15 @@ public abstract class AbstractNamedValueMethodArgumentResolver implements Handle
* Resolves the given default value into an argument value.
*/
private Object resolveDefaultValue(String defaultValue) {
- if (beanFactory == null) {
+ if (this.configurableBeanFactory == null) {
return defaultValue;
}
- String placeholdersResolved = beanFactory.resolveEmbeddedValue(defaultValue);
- BeanExpressionResolver exprResolver = beanFactory.getBeanExpressionResolver();
+ String placeholdersResolved = this.configurableBeanFactory.resolveEmbeddedValue(defaultValue);
+ BeanExpressionResolver exprResolver = this.configurableBeanFactory.getBeanExpressionResolver();
if (exprResolver == null) {
return defaultValue;
}
- return exprResolver.evaluate(placeholdersResolved, expressionContext);
+ return exprResolver.evaluate(placeholdersResolved, this.expressionContext);
}
/**
diff --git a/org.springframework.web/src/main/java/org/springframework/web/method/annotation/support/MapMethodProcessor.java b/org.springframework.web/src/main/java/org/springframework/web/method/annotation/support/MapMethodProcessor.java
new file mode 100644
index 0000000000..bd265bb9a5
--- /dev/null
+++ b/org.springframework.web/src/main/java/org/springframework/web/method/annotation/support/MapMethodProcessor.java
@@ -0,0 +1,73 @@
+/*
+ * Copyright 2002-2011 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.springframework.web.method.annotation.support;
+
+import java.util.Map;
+
+import org.springframework.core.MethodParameter;
+import org.springframework.web.bind.support.WebDataBinderFactory;
+import org.springframework.web.context.request.NativeWebRequest;
+import org.springframework.web.method.support.HandlerMethodArgumentResolver;
+import org.springframework.web.method.support.HandlerMethodReturnValueHandler;
+import org.springframework.web.method.support.ModelAndViewContainer;
+
+/**
+ * Resolves {@link Map} method arguments and handles {@link Map} return values.
+ *
+ *
A Map return value can be interpreted in more than one ways depending
+ * on the presence of annotations like {@code @ModelAttribute} or
+ * {@code @ResponseBody}. Therefore this handler should be configured after
+ * the handlers that support these annotations.
+ *
+ * @author Rossen Stoyanchev
+ * @since 3.1
+ */
+public class MapMethodProcessor implements HandlerMethodArgumentResolver, HandlerMethodReturnValueHandler {
+
+ public boolean supportsParameter(MethodParameter parameter) {
+ return Map.class.isAssignableFrom(parameter.getParameterType());
+ }
+
+ public Object resolveArgument(MethodParameter parameter,
+ ModelAndViewContainer mavContainer,
+ NativeWebRequest webRequest,
+ WebDataBinderFactory binderFactory) throws Exception {
+ return mavContainer.getModel();
+ }
+
+ public boolean supportsReturnType(MethodParameter returnType) {
+ return Map.class.isAssignableFrom(returnType.getParameterType());
+ }
+
+ @SuppressWarnings({ "unchecked", "rawtypes" })
+ public void handleReturnValue(Object returnValue,
+ MethodParameter returnType,
+ ModelAndViewContainer mavContainer,
+ NativeWebRequest webRequest) throws Exception {
+ if (returnValue == null) {
+ return;
+ }
+ else if (returnValue instanceof Map){
+ mavContainer.addAllAttributes((Map) returnValue);
+ }
+ else {
+ // should not happen
+ throw new UnsupportedOperationException("Unexpected return type: " +
+ returnType.getParameterType().getName() + " in method: " + returnType.getMethod());
+ }
+ }
+}
\ No newline at end of file
diff --git a/org.springframework.web/src/main/java/org/springframework/web/method/annotation/support/ModelMethodProcessor.java b/org.springframework.web/src/main/java/org/springframework/web/method/annotation/support/ModelMethodProcessor.java
index ce0da85ed4..2e175e4a67 100644
--- a/org.springframework.web/src/main/java/org/springframework/web/method/annotation/support/ModelMethodProcessor.java
+++ b/org.springframework.web/src/main/java/org/springframework/web/method/annotation/support/ModelMethodProcessor.java
@@ -16,12 +16,8 @@
package org.springframework.web.method.annotation.support;
-import java.lang.reflect.Method;
-import java.util.Map;
-
import org.springframework.core.MethodParameter;
import org.springframework.ui.Model;
-import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.support.WebDataBinderFactory;
import org.springframework.web.context.request.NativeWebRequest;
import org.springframework.web.method.support.HandlerMethodArgumentResolver;
@@ -29,12 +25,12 @@ import org.springframework.web.method.support.HandlerMethodReturnValueHandler;
import org.springframework.web.method.support.ModelAndViewContainer;
/**
- * Resolves {@link Map} and {@link Model} method arguments.
+ * Resolves {@link Model} method arguments and handles {@link Model} return values.
*
- *
Handles {@link Model} return values adding their attributes to the {@link ModelAndViewContainer}.
- * Handles {@link Map} return values in the same way as long as the method does not have an @{@link ModelAttribute}.
- * If the method does have an @{@link ModelAttribute}, it is assumed the returned {@link Map} is a model attribute
- * and not a model.
+ *
A {@link Model} return type has a set purpose. Therefore this handler
+ * should be configured ahead of handlers that support any return value type
+ * annotated with {@code @ModelAttribute} or {@code @ResponseBody} to ensure
+ * they don't take over.
*
* @author Rossen Stoyanchev
* @since 3.1
@@ -42,8 +38,7 @@ import org.springframework.web.method.support.ModelAndViewContainer;
public class ModelMethodProcessor implements HandlerMethodArgumentResolver, HandlerMethodReturnValueHandler {
public boolean supportsParameter(MethodParameter parameter) {
- Class> paramType = parameter.getParameterType();
- return Model.class.isAssignableFrom(paramType) || Map.class.isAssignableFrom(paramType);
+ return Model.class.isAssignableFrom(parameter.getParameterType());
}
public Object resolveArgument(MethodParameter parameter,
@@ -54,12 +49,9 @@ public class ModelMethodProcessor implements HandlerMethodArgumentResolver, Hand
}
public boolean supportsReturnType(MethodParameter returnType) {
- Class> paramType = returnType.getParameterType();
- boolean hasModelAttr = returnType.getMethodAnnotation(ModelAttribute.class) != null;
- return (Model.class.isAssignableFrom(paramType) || (Map.class.isAssignableFrom(paramType) && !hasModelAttr));
+ return Model.class.isAssignableFrom(returnType.getParameterType());
}
- @SuppressWarnings({ "unchecked", "rawtypes" })
public void handleReturnValue(Object returnValue,
MethodParameter returnType,
ModelAndViewContainer mavContainer,
@@ -67,17 +59,13 @@ public class ModelMethodProcessor implements HandlerMethodArgumentResolver, Hand
if (returnValue == null) {
return;
}
- if (returnValue instanceof Model) {
+ else if (returnValue instanceof Model) {
mavContainer.addAllAttributes(((Model) returnValue).asMap());
}
- else if (returnValue instanceof Map){
- mavContainer.addAllAttributes((Map) returnValue);
- }
else {
// should not happen
- Method method = returnType.getMethod();
- String returnTypeName = returnType.getParameterType().getName();
- throw new UnsupportedOperationException("Unknown return type: " + returnTypeName + " in method: " + method);
+ throw new UnsupportedOperationException("Unexpected return type: " +
+ returnType.getParameterType().getName() + " in method: " + returnType.getMethod());
}
}
}
\ No newline at end of file
diff --git a/org.springframework.web/src/main/java/org/springframework/web/method/annotation/support/SessionStatusMethodArgumentResolver.java b/org.springframework.web/src/main/java/org/springframework/web/method/annotation/support/SessionStatusMethodArgumentResolver.java
new file mode 100644
index 0000000000..895bf5022d
--- /dev/null
+++ b/org.springframework.web/src/main/java/org/springframework/web/method/annotation/support/SessionStatusMethodArgumentResolver.java
@@ -0,0 +1,46 @@
+/*
+ * Copyright 2002-2011 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.springframework.web.method.annotation.support;
+
+import org.springframework.core.MethodParameter;
+import org.springframework.web.bind.support.SessionStatus;
+import org.springframework.web.bind.support.WebDataBinderFactory;
+import org.springframework.web.context.request.NativeWebRequest;
+import org.springframework.web.method.support.HandlerMethodArgumentResolver;
+import org.springframework.web.method.support.ModelAndViewContainer;
+
+/**
+ * Resolves {@link SessionStatus} arguments by obtaining it from the
+ * {@link ModelAndViewContainer}.
+ *
+ * @author Rossen Stoyanchev
+ * @since 3.1
+ */
+public class SessionStatusMethodArgumentResolver implements HandlerMethodArgumentResolver {
+
+ public boolean supportsParameter(MethodParameter parameter) {
+ return SessionStatus.class.equals(parameter.getParameterType());
+ }
+
+ public Object resolveArgument(MethodParameter parameter,
+ ModelAndViewContainer mavContainer,
+ NativeWebRequest webRequest,
+ WebDataBinderFactory binderFactory) throws Exception {
+ return mavContainer.getSessionStatus();
+ }
+
+}
diff --git a/org.springframework.web/src/main/java/org/springframework/web/method/support/HandlerMethodArgumentResolverComposite.java b/org.springframework.web/src/main/java/org/springframework/web/method/support/HandlerMethodArgumentResolverComposite.java
index 82b04f2cd9..c6c6f8ee33 100644
--- a/org.springframework.web/src/main/java/org/springframework/web/method/support/HandlerMethodArgumentResolverComposite.java
+++ b/org.springframework.web/src/main/java/org/springframework/web/method/support/HandlerMethodArgumentResolverComposite.java
@@ -17,6 +17,7 @@
package org.springframework.web.method.support;
import java.util.ArrayList;
+import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
@@ -45,6 +46,13 @@ public class HandlerMethodArgumentResolverComposite implements HandlerMethodArgu
private final Map argumentResolverCache =
new ConcurrentHashMap();
+ /**
+ * Return a read-only list with the contained resolvers, or an empty list.
+ */
+ public List getResolvers() {
+ return Collections.unmodifiableList(this.argumentResolvers);
+ }
+
/**
* Whether the given {@linkplain MethodParameter method parameter} is supported by any registered
* {@link HandlerMethodArgumentResolver}.
@@ -90,19 +98,22 @@ public class HandlerMethodArgumentResolverComposite implements HandlerMethodArgu
/**
* Add the given {@link HandlerMethodArgumentResolver}.
*/
- public void addResolver(HandlerMethodArgumentResolver argumentResolver) {
+ public HandlerMethodArgumentResolverComposite addResolver(HandlerMethodArgumentResolver argumentResolver) {
this.argumentResolvers.add(argumentResolver);
+ return this;
}
/**
* Add the given {@link HandlerMethodArgumentResolver}s.
*/
- public void addResolvers(List extends HandlerMethodArgumentResolver> argumentResolvers) {
+ public HandlerMethodArgumentResolverComposite addResolvers(
+ List extends HandlerMethodArgumentResolver> argumentResolvers) {
if (argumentResolvers != null) {
for (HandlerMethodArgumentResolver resolver : argumentResolvers) {
this.argumentResolvers.add(resolver);
}
}
+ return this;
}
}
\ No newline at end of file
diff --git a/org.springframework.web/src/main/java/org/springframework/web/method/support/HandlerMethodReturnValueHandlerComposite.java b/org.springframework.web/src/main/java/org/springframework/web/method/support/HandlerMethodReturnValueHandlerComposite.java
index a6f8a57477..7652c879ef 100644
--- a/org.springframework.web/src/main/java/org/springframework/web/method/support/HandlerMethodReturnValueHandlerComposite.java
+++ b/org.springframework.web/src/main/java/org/springframework/web/method/support/HandlerMethodReturnValueHandlerComposite.java
@@ -17,6 +17,7 @@
package org.springframework.web.method.support;
import java.util.ArrayList;
+import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
@@ -44,6 +45,13 @@ public class HandlerMethodReturnValueHandlerComposite implements HandlerMethodRe
private final Map returnValueHandlerCache =
new ConcurrentHashMap();
+ /**
+ * Return a read-only list with the registered handlers, or an empty list.
+ */
+ public List getHandlers() {
+ return Collections.unmodifiableList(this.returnValueHandlers);
+ }
+
/**
* Whether the given {@linkplain MethodParameter method return type} is supported by any registered
* {@link HandlerMethodReturnValueHandler}.
@@ -89,19 +97,22 @@ public class HandlerMethodReturnValueHandlerComposite implements HandlerMethodRe
/**
* Add the given {@link HandlerMethodReturnValueHandler}.
*/
- public void addHandler(HandlerMethodReturnValueHandler returnValuehandler) {
+ public HandlerMethodReturnValueHandlerComposite addHandler(HandlerMethodReturnValueHandler returnValuehandler) {
returnValueHandlers.add(returnValuehandler);
+ return this;
}
/**
* Add the given {@link HandlerMethodReturnValueHandler}s.
*/
- public void addHandlers(List extends HandlerMethodReturnValueHandler> returnValueHandlers) {
+ public HandlerMethodReturnValueHandlerComposite addHandlers(
+ List extends HandlerMethodReturnValueHandler> returnValueHandlers) {
if (returnValueHandlers != null) {
for (HandlerMethodReturnValueHandler handler : returnValueHandlers) {
this.returnValueHandlers.add(handler);
}
}
+ return this;
}
}
\ No newline at end of file
diff --git a/org.springframework.web/src/main/java/org/springframework/web/method/support/ModelAndViewContainer.java b/org.springframework.web/src/main/java/org/springframework/web/method/support/ModelAndViewContainer.java
index 8efcd1a0b8..94096df006 100644
--- a/org.springframework.web/src/main/java/org/springframework/web/method/support/ModelAndViewContainer.java
+++ b/org.springframework.web/src/main/java/org/springframework/web/method/support/ModelAndViewContainer.java
@@ -21,6 +21,8 @@ import java.util.Map;
import org.springframework.ui.Model;
import org.springframework.ui.ModelMap;
import org.springframework.validation.support.BindingAwareModelMap;
+import org.springframework.web.bind.support.SessionStatus;
+import org.springframework.web.bind.support.SimpleSessionStatus;
/**
* Records model and view related decisions made by
@@ -33,7 +35,7 @@ import org.springframework.validation.support.BindingAwareModelMap;
*
*
A default {@link Model} is automatically created at instantiation.
* An alternate model instance may be provided via {@link #setRedirectModel}
- * for use in a redirect scenario. When {@link #setUseRedirectModel} is set
+ * for use in a redirect scenario. When {@link #setRedirectModelScenario} is set
* to {@code true} signalling a redirect scenario, the {@link #getModel()}
* returns the redirect model instead of the default model.
*
@@ -46,14 +48,16 @@ public class ModelAndViewContainer {
private boolean requestHandled = false;
- private final ModelMap model = new BindingAwareModelMap();
+ private final ModelMap defaultModel = new BindingAwareModelMap();
private ModelMap redirectModel;
- private boolean ignoreDefaultModelOnRedirect = false;
-
- private boolean useRedirectModel = false;
+ private boolean redirectModelScenario = false;
+ private boolean ignoreDefaultModelOnRedirect = false;
+
+ private final SessionStatus sessionStatus = new SimpleSessionStatus();
+
/**
* Create a new instance.
*/
@@ -123,34 +127,45 @@ public class ModelAndViewContainer {
}
/**
- * Return the model to use. This is either the default model created at
- * instantiation or the redirect model if {@link #setUseRedirectModel}
- * is set to {@code true}. If a redirect model was never provided via
- * {@link #setRedirectModel}, return the default model unless
- * {@link #setIgnoreDefaultModelOnRedirect} is set to {@code true}.
+ * Return the model to use: the "default" or the "redirect" model.
+ *
The default model is used if {@code "redirectModelScenario=false"} or
+ * if the redirect model is {@code null} (i.e. it wasn't declared as a
+ * method argument) and {@code ignoreDefaultModelOnRedirect=false}.
*/
public ModelMap getModel() {
- if (!this.useRedirectModel) {
- return this.model;
- }
- else if (this.redirectModel != null) {
- return this.redirectModel;
+ if (useDefaultModel()) {
+ return this.defaultModel;
}
else {
- return this.ignoreDefaultModelOnRedirect ? new ModelMap() : this.model;
+ return (this.redirectModel != null) ? this.redirectModel : new ModelMap();
}
}
+ /**
+ * Whether to use the default model or the redirect model.
+ */
+ private boolean useDefaultModel() {
+ return !this.redirectModelScenario || ((this.redirectModel == null) && !this.ignoreDefaultModelOnRedirect);
+ }
+
/**
* Provide a separate model instance to use in a redirect scenario.
* The provided additional model however is not used used unless
- * {@link #setUseRedirectModel(boolean)} gets set to {@code true} to signal
+ * {@link #setRedirectModelScenario(boolean)} gets set to {@code true} to signal
* a redirect scenario.
*/
public void setRedirectModel(ModelMap redirectModel) {
this.redirectModel = redirectModel;
}
+ /**
+ * Signal the conditions are in place for using a redirect model.
+ * Typically that means the controller has returned a redirect instruction.
+ */
+ public void setRedirectModelScenario(boolean redirectModelScenario) {
+ this.redirectModelScenario = redirectModelScenario;
+ }
+
/**
* When set to {@code true} the default model is never used in a redirect
* scenario. So if a redirect model is not available, an empty model is
@@ -164,11 +179,11 @@ public class ModelAndViewContainer {
}
/**
- * Signal the conditions for using a redirect model are in place -- e.g.
- * the controller has requested a redirect.
+ * Return the {@link SessionStatus} instance to use that can be used to
+ * signal that session processing is complete.
*/
- public void setUseRedirectModel(boolean useRedirectModel) {
- this.useRedirectModel = useRedirectModel;
+ public SessionStatus getSessionStatus() {
+ return sessionStatus;
}
/**
@@ -229,7 +244,13 @@ public class ModelAndViewContainer {
else {
sb.append("View is [").append(this.view).append(']');
}
- sb.append("; model is ").append(getModel());
+ if (useDefaultModel()) {
+ sb.append("; default model ");
+ }
+ else {
+ sb.append("; redirect model ");
+ }
+ sb.append(getModel());
}
else {
sb.append("Request handled directly");
diff --git a/org.springframework.web/src/test/java/org/springframework/web/method/annotation/ModelFactoryTests.java b/org.springframework.web/src/test/java/org/springframework/web/method/annotation/ModelFactoryTests.java
index df0eb30b8e..6357216c03 100644
--- a/org.springframework.web/src/test/java/org/springframework/web/method/annotation/ModelFactoryTests.java
+++ b/org.springframework.web/src/test/java/org/springframework/web/method/annotation/ModelFactoryTests.java
@@ -41,8 +41,6 @@ import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.SessionAttributes;
import org.springframework.web.bind.support.DefaultSessionAttributeStore;
import org.springframework.web.bind.support.SessionAttributeStore;
-import org.springframework.web.bind.support.SessionStatus;
-import org.springframework.web.bind.support.SimpleSessionStatus;
import org.springframework.web.bind.support.WebDataBinderFactory;
import org.springframework.web.context.request.NativeWebRequest;
import org.springframework.web.context.request.ServletWebRequest;
@@ -161,7 +159,7 @@ public class ModelFactoryTests {
replay(binderFactory);
ModelFactory modelFactory = new ModelFactory(null, binderFactory, sessionAttrsHandler);
- modelFactory.updateModel(webRequest, mavContainer, new SimpleSessionStatus());
+ modelFactory.updateModel(webRequest, mavContainer);
assertEquals(attrValue, mavContainer.getModel().remove(attrName));
assertSame(dataBinder.getBindingResult(), mavContainer.getModel().remove(bindingResultKey(attrName)));
@@ -177,6 +175,7 @@ public class ModelFactoryTests {
ModelAndViewContainer mavContainer = new ModelAndViewContainer();
mavContainer.addAttribute(attrName, attrValue);
+ mavContainer.getSessionStatus().setComplete();
sessionAttributeStore.storeAttribute(webRequest, attrName, attrValue);
// Resolve successfully handler session attribute once
@@ -187,11 +186,8 @@ public class ModelFactoryTests {
expect(binderFactory.createBinder(webRequest, attrValue, attrName)).andReturn(dataBinder);
replay(binderFactory);
- SessionStatus sessionStatus = new SimpleSessionStatus();
- sessionStatus.setComplete();
-
ModelFactory modelFactory = new ModelFactory(null, binderFactory, sessionAttrsHandler);
- modelFactory.updateModel(webRequest, mavContainer, sessionStatus);
+ modelFactory.updateModel(webRequest, mavContainer);
assertEquals(attrValue, mavContainer.getModel().get(attrName));
assertNull(sessionAttributeStore.retrieveAttribute(webRequest, attrName));
diff --git a/org.springframework.web/src/test/java/org/springframework/web/method/annotation/support/MapMethodProcessorTests.java b/org.springframework.web/src/test/java/org/springframework/web/method/annotation/support/MapMethodProcessorTests.java
new file mode 100644
index 0000000000..475e57fd03
--- /dev/null
+++ b/org.springframework.web/src/test/java/org/springframework/web/method/annotation/support/MapMethodProcessorTests.java
@@ -0,0 +1,95 @@
+/*
+ * Copyright 2002-2011 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.springframework.web.method.annotation.support;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertSame;
+import static org.junit.Assert.assertTrue;
+
+import java.lang.reflect.Method;
+import java.util.Map;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.springframework.core.MethodParameter;
+import org.springframework.mock.web.MockHttpServletRequest;
+import org.springframework.ui.ModelMap;
+import org.springframework.web.context.request.NativeWebRequest;
+import org.springframework.web.context.request.ServletWebRequest;
+import org.springframework.web.method.support.ModelAndViewContainer;
+
+/**
+ * Test fixture with {@link MapMethodProcessor}.
+ *
+ * @author Rossen Stoyanchev
+ */
+public class MapMethodProcessorTests {
+
+ private MapMethodProcessor processor;
+
+ private ModelAndViewContainer mavContainer;
+
+ private MethodParameter paramMap;
+
+ private MethodParameter returnParamMap;
+
+ private NativeWebRequest webRequest;
+
+ @Before
+ public void setUp() throws Exception {
+ processor = new MapMethodProcessor();
+ mavContainer = new ModelAndViewContainer();
+
+ Method method = getClass().getDeclaredMethod("map", Map.class);
+ paramMap = new MethodParameter(method, 0);
+ returnParamMap = new MethodParameter(method, 0);
+
+ webRequest = new ServletWebRequest(new MockHttpServletRequest());
+ }
+
+ @Test
+ public void supportsParameter() {
+ assertTrue(processor.supportsParameter(paramMap));
+ }
+
+ @Test
+ public void supportsReturnType() {
+ assertTrue(processor.supportsReturnType(returnParamMap));
+ }
+
+ @Test
+ public void resolveArgumentValue() throws Exception {
+ assertSame(mavContainer.getModel(), processor.resolveArgument(paramMap, mavContainer, webRequest, null));
+ }
+
+ @Test
+ public void handleMapReturnValue() throws Exception {
+ mavContainer.addAttribute("attr1", "value1");
+ Map returnValue = new ModelMap("attr2", "value2");
+
+ processor.handleReturnValue(returnValue , returnParamMap, mavContainer, webRequest);
+
+ assertEquals("value1", mavContainer.getModel().get("attr1"));
+ assertEquals("value2", mavContainer.getModel().get("attr2"));
+ }
+
+ @SuppressWarnings("unused")
+ private Map map(Map map) {
+ return null;
+ }
+
+}
\ No newline at end of file
diff --git a/org.springframework.web/src/test/java/org/springframework/web/method/annotation/support/ModelMethodProcessorTests.java b/org.springframework.web/src/test/java/org/springframework/web/method/annotation/support/ModelMethodProcessorTests.java
index fa830f1057..108bec635d 100644
--- a/org.springframework.web/src/test/java/org/springframework/web/method/annotation/support/ModelMethodProcessorTests.java
+++ b/org.springframework.web/src/test/java/org/springframework/web/method/annotation/support/ModelMethodProcessorTests.java
@@ -21,14 +21,13 @@ import static org.junit.Assert.assertSame;
import static org.junit.Assert.assertTrue;
import java.lang.reflect.Method;
-import java.util.Map;
import org.junit.Before;
import org.junit.Test;
import org.springframework.core.MethodParameter;
import org.springframework.mock.web.MockHttpServletRequest;
+import org.springframework.ui.ExtendedModelMap;
import org.springframework.ui.Model;
-import org.springframework.ui.ModelMap;
import org.springframework.web.context.request.NativeWebRequest;
import org.springframework.web.context.request.ServletWebRequest;
import org.springframework.web.method.support.ModelAndViewContainer;
@@ -48,10 +47,6 @@ public class ModelMethodProcessorTests {
private MethodParameter returnParamModel;
- private MethodParameter paramMap;
-
- private MethodParameter returnParamMap;
-
private NativeWebRequest webRequest;
@Before
@@ -63,64 +58,39 @@ public class ModelMethodProcessorTests {
paramModel = new MethodParameter(method, 0);
returnParamModel = new MethodParameter(method, -1);
- method = getClass().getDeclaredMethod("map", Map.class);
- paramMap = new MethodParameter(method, 0);
- returnParamMap = new MethodParameter(method, 0);
-
webRequest = new ServletWebRequest(new MockHttpServletRequest());
}
@Test
public void supportsParameter() {
assertTrue(processor.supportsParameter(paramModel));
- assertTrue(processor.supportsParameter(paramMap));
}
@Test
public void supportsReturnType() {
assertTrue(processor.supportsReturnType(returnParamModel));
- assertTrue(processor.supportsReturnType(returnParamMap));
}
@Test
public void resolveArgumentValue() throws Exception {
- Object result = processor.resolveArgument(paramModel, mavContainer, webRequest, null);
- assertSame(mavContainer.getModel(), result);
-
- result = processor.resolveArgument(paramMap, mavContainer, webRequest, null);
- assertSame(mavContainer.getModel(), result);
+ assertSame(mavContainer.getModel(), processor.resolveArgument(paramModel, mavContainer, webRequest, null));
}
@Test
public void handleModelReturnValue() throws Exception {
mavContainer.addAttribute("attr1", "value1");
- ModelMap returnValue = new ModelMap("attr2", "value2");
+ Model returnValue = new ExtendedModelMap();
+ returnValue.addAttribute("attr2", "value2");
processor.handleReturnValue(returnValue , returnParamModel, mavContainer, webRequest);
assertEquals("value1", mavContainer.getModel().get("attr1"));
assertEquals("value2", mavContainer.getModel().get("attr2"));
}
-
- @Test
- public void handleMapReturnValue() throws Exception {
- mavContainer.addAttribute("attr1", "value1");
- Map returnValue = new ModelMap("attr2", "value2");
-
- processor.handleReturnValue(returnValue , returnParamMap, mavContainer, webRequest);
-
- assertEquals("value1", mavContainer.getModel().get("attr1"));
- assertEquals("value2", mavContainer.getModel().get("attr2"));
- }
@SuppressWarnings("unused")
private Model model(Model model) {
return null;
}
-
- @SuppressWarnings("unused")
- private Map map(Map map) {
- return null;
- }
}
\ No newline at end of file
diff --git a/org.springframework.web/src/test/java/org/springframework/web/method/support/ModelAndViewContainerTests.java b/org.springframework.web/src/test/java/org/springframework/web/method/support/ModelAndViewContainerTests.java
index cd369258b9..7e98d2c4e6 100644
--- a/org.springframework.web/src/test/java/org/springframework/web/method/support/ModelAndViewContainerTests.java
+++ b/org.springframework.web/src/test/java/org/springframework/web/method/support/ModelAndViewContainerTests.java
@@ -52,7 +52,7 @@ public class ModelAndViewContainerTests {
assertEquals("Default model should be used if not in redirect scenario",
"value", this.mavContainer.getModel().get("name"));
- this.mavContainer.setUseRedirectModel(true);
+ this.mavContainer.setRedirectModelScenario(true);
assertEquals("Redirect model should be used in redirect scenario",
"redirectValue", this.mavContainer.getModel().get("name"));
@@ -61,7 +61,7 @@ public class ModelAndViewContainerTests {
@Test
public void getModelIgnoreDefaultModelOnRedirect() {
this.mavContainer.addAttribute("name", "value");
- this.mavContainer.setUseRedirectModel(true);
+ this.mavContainer.setRedirectModelScenario(true);
assertEquals("Default model should be used since no redirect model was provided",
1, this.mavContainer.getModel().size());