diff --git a/org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/mvc/method/annotation/RequestMappingHandlerMethodAdapter.java b/org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/mvc/method/annotation/RequestMappingHandlerMethodAdapter.java index 979863d0e4..877f29f59b 100644 --- a/org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/mvc/method/annotation/RequestMappingHandlerMethodAdapter.java +++ b/org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/mvc/method/annotation/RequestMappingHandlerMethodAdapter.java @@ -42,9 +42,11 @@ import org.springframework.http.converter.StringHttpMessageConverter; import org.springframework.http.converter.xml.SourceHttpMessageConverter; import org.springframework.http.converter.xml.XmlAwareFormHttpMessageConverter; import org.springframework.util.ReflectionUtils.MethodFilter; +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.annotation.SessionAttributes; import org.springframework.web.bind.support.DefaultDataBinderFactory; import org.springframework.web.bind.support.DefaultSessionAttributeStore; import org.springframework.web.bind.support.SessionAttributeStore; @@ -56,6 +58,7 @@ import org.springframework.web.bind.support.WebDataBinderFactory; import org.springframework.web.context.request.ServletWebRequest; import org.springframework.web.method.HandlerMethod; import org.springframework.web.method.HandlerMethodSelector; +import org.springframework.web.method.annotation.InitBinderMethodDataBinderFactory; import org.springframework.web.method.annotation.ModelFactory; import org.springframework.web.method.annotation.SessionAttributesHandler; import org.springframework.web.method.annotation.support.ErrorsMethodArgumentResolver; @@ -90,10 +93,30 @@ import org.springframework.web.servlet.mvc.method.annotation.support.ViewMethodR import org.springframework.web.util.WebUtils; /** - * An extension of {@link AbstractHandlerMethodAdapter} with support for {@link RequestMapping} handler methods. + * A {@link AbstractHandlerMethodAdapter} variant with support for invoking {@link RequestMapping} handler methods. + * + *

Invoking a {@link RequestMapping} method typically involves the invocation of other handler methods such as + * {@link ModelAttribute} methods for contributing attributes to the model and {@link InitBinder} methods for + * initializing {@link WebDataBinder} instances for data binding and type conversion purposes. + * + *

{@link InvocableHandlerMethod} is the key contributing class that helps with the invocation of any handler + * method after resolving its arguments through a set of {@link HandlerMethodArgumentResolver}s. + * {@link ServletInvocableHandlerMethod} on the other hand, handles the return value through a set of + * {@link HandlerMethodReturnValueHandler}s resulting in a {@link ModelAndView} when view resolution applies. + * + *

Specifically assisting with the invocation of {@link ModelAttribute} methods is the {@link ModelFactory} while + * the invocation of {@link InitBinder} methods is done with the help of the {@link InitBinderMethodDataBinderFactory}, + * which is passed on to {@link HandlerMethodArgumentResolver}s where data binder instances are needed. + * + *

This class is the central point that assembles all of the above mentioned contributors and drives them while + * also invoking the actual {@link RequestMapping} handler method through a {@link ServletInvocableHandlerMethod}. * * @author Rossen Stoyanchev * @since 3.1 + * @see InvocableHandlerMethod + * @see ServletInvocableHandlerMethod + * @see HandlerMethodArgumentResolver + * @see HandlerMethodReturnValueHandler */ public class RequestMappingHandlerMethodAdapter extends AbstractHandlerMethodAdapter implements BeanFactoryAware, InitializingBean { @@ -142,37 +165,23 @@ public class RequestMappingHandlerMethodAdapter extends AbstractHandlerMethodAda new XmlAwareFormHttpMessageConverter() }; } - /** - * Set a custom WebArgumentResolvers to use for special method parameter types. - *

Such a custom WebArgumentResolver will kick in first, having a chance to resolve - * an argument value before the standard argument handling kicks in. - */ - public void setCustomArgumentResolver(WebArgumentResolver argumentResolver) { - this.customArgumentResolvers = new WebArgumentResolver[] {argumentResolver}; - } - /** * Set one or more custom WebArgumentResolvers to use for special method parameter types. *

Any such custom WebArgumentResolver will kick in first, having a chance to resolve * an argument value before the standard argument handling kicks in. + *

Note: this is provided for backward compatibility. The preferred way to do this is to + * implement a {@link HandlerMethodArgumentResolver}. */ public void setCustomArgumentResolvers(WebArgumentResolver[] argumentResolvers) { this.customArgumentResolvers = argumentResolvers; } - /** - * Set a custom ModelAndViewResolvers to use for special method return types. - *

Such a custom ModelAndViewResolver will kick in first, having a chance to resolve - * a return value before the standard ModelAndView handling kicks in. - */ - public void setCustomModelAndViewResolver(ModelAndViewResolver customModelAndViewResolver) { - this.customModelAndViewResolvers = new ModelAndViewResolver[] {customModelAndViewResolver}; - } - /** * Set one or more custom ModelAndViewResolvers to use for special method return types. *

Any such custom ModelAndViewResolver will kick in first, having a chance to resolve * a return value before the standard ModelAndView handling kicks in. + *

Note: this is provided for backward compatibility. The preferred way to do this is to + * implement a {@link HandlerMethodReturnValueHandler}. */ public void setCustomModelAndViewResolvers(ModelAndViewResolver[] customModelAndViewResolvers) { this.customModelAndViewResolvers = customModelAndViewResolvers; @@ -436,6 +445,10 @@ public class RequestMappingHandlerMethodAdapter extends AbstractHandlerMethodAda return invokeHandlerMethod(request, response, handlerMethod); } + /** + * Whether the given handler type defines any handler-specific session attributes via {@link SessionAttributes}. + * Also initializes the sessionAttributesHandlerCache for the given handler type. + */ private boolean hasSessionAttributes(Class handlerType) { SessionAttributesHandler handler = null; synchronized(this.sessionAttributesHandlerCache) { @@ -448,6 +461,9 @@ public class RequestMappingHandlerMethodAdapter extends AbstractHandlerMethodAda return handler.hasSessionAttributes(); } + /** + * Invoke the {@link RequestMapping} handler method preparing a {@link ModelAndView} if view resolution is required. + */ private ModelAndView invokeHandlerMethod(HttpServletRequest request, HttpServletResponse response, HandlerMethod handlerMethod) throws Exception { @@ -556,4 +572,4 @@ public class RequestMappingHandlerMethodAdapter extends AbstractHandlerMethodAda } }; -} +} \ No newline at end of file diff --git a/org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/mvc/method/annotation/RequestMappingHandlerMethodExceptionResolver.java b/org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/mvc/method/annotation/RequestMappingHandlerMethodExceptionResolver.java index a32e19003d..c89f106a48 100644 --- a/org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/mvc/method/annotation/RequestMappingHandlerMethodExceptionResolver.java +++ b/org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/mvc/method/annotation/RequestMappingHandlerMethodExceptionResolver.java @@ -34,6 +34,7 @@ import org.springframework.http.converter.xml.SourceHttpMessageConverter; import org.springframework.http.converter.xml.XmlAwareFormHttpMessageConverter; import org.springframework.util.ReflectionUtils.MethodFilter; import org.springframework.web.bind.annotation.ExceptionHandler; +import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.support.WebArgumentResolver; import org.springframework.web.context.request.ServletWebRequest; import org.springframework.web.method.HandlerMethod; @@ -59,12 +60,19 @@ import org.springframework.web.servlet.mvc.method.annotation.support.ServletWebA import org.springframework.web.servlet.mvc.method.annotation.support.ViewMethodReturnValueHandler; /** - * A {@link AbstractHandlerMethodExceptionResolver} that matches thrown exceptions to {@link ExceptionHandler}-annotated - * methods. If a match is found the exception-handling method is invoked to process the request. + * An {@link AbstractHandlerMethodExceptionResolver} that looks for an {@link ExceptionHandler}-annotated method + * that can handle a thrown exception. If a match is found the exception-handling method is invoked to finish + * processing the request. * - *

See {@link ExceptionHandler} for information on supported method arguments and return values for exception-handling - * methods. You can customize method argument resolution and return value processing through the various bean properties - * in this class. + *

{@link ExceptionMethodMapping} is a key contributing class storing method-to-exception type mappings extracted + * from {@link ExceptionHandler} annotations or from the list of method arguments on the exception-handling method. + * {@link ExceptionMethodMapping} assists with actually locating a method for a thrown exception. + * + *

Once located the invocation of the exception-handling method is done using much of the same classes + * used for {@link RequestMapping} methods, which is described under {@link RequestMappingHandlerMethodAdapter}. + * + *

See {@link ExceptionHandler} for information on supported method arguments and return values for + * exception-handling methods. * * @author Rossen Stoyanchev * @since 3.1 @@ -96,17 +104,6 @@ public class RequestMappingHandlerMethodExceptionResolver extends AbstractHandle new XmlAwareFormHttpMessageConverter() }; } - /** - * Set a custom ArgumentResolver to use for special method parameter types. - *

Such a custom ArgumentResolver will kick in first, having a chance to resolve - * an argument value before the standard argument handling kicks in. - *

Note: this is provided for backward compatibility. The preferred way to do this is to - * implement a {@link HandlerMethodArgumentResolver}. - */ - public void setCustomArgumentResolver(WebArgumentResolver argumentResolver) { - this.customArgumentResolvers = new WebArgumentResolver[]{argumentResolver}; - } - /** * Set one or more custom ArgumentResolvers to use for special method parameter types. *

Any such custom ArgumentResolver will kick in first, having a chance to resolve diff --git a/org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/mvc/method/annotation/ServletInvocableHandlerMethod.java b/org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/mvc/method/annotation/ServletInvocableHandlerMethod.java index 481ee47467..d7b204a8b4 100644 --- a/org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/mvc/method/annotation/ServletInvocableHandlerMethod.java +++ b/org.springframework.web.servlet/src/main/java/org/springframework/web/servlet/mvc/method/annotation/ServletInvocableHandlerMethod.java @@ -33,18 +33,10 @@ import org.springframework.web.servlet.View; /** * Extends {@link InvocableHandlerMethod} with the ability to handle the return value through registered - * {@link HandlerMethodArgumentResolver}s. If the handler method is annotated with {@link ResponseStatus}, - * the status on the response is set accordingly after method invocation but before return value handling. + * {@link HandlerMethodArgumentResolver}s. * - *

Return value handling may be skipped entirely if the handler method returns a {@code null} (or is a - * {@code void} method) and one of the following other conditions is true: - *

+ *

The {@link ModelAndViewContainer} for the request contains the results from the handling of the return value. + * It can be used to access model attributes and view selection and to check if view resolution is needed. * * @author Rossen Stoyanchev * @since 3.1 diff --git a/org.springframework.web.servlet/src/test/java/org/springframework/web/servlet/mvc/method/annotation/ServletHandlerMethodTests.java b/org.springframework.web.servlet/src/test/java/org/springframework/web/servlet/mvc/method/annotation/ServletHandlerMethodTests.java index d6668915ef..7ab467fd5b 100644 --- a/org.springframework.web.servlet/src/test/java/org/springframework/web/servlet/mvc/method/annotation/ServletHandlerMethodTests.java +++ b/org.springframework.web.servlet/src/test/java/org/springframework/web/servlet/mvc/method/annotation/ServletHandlerMethodTests.java @@ -575,7 +575,8 @@ public class ServletHandlerMethodTests { wac.registerBeanDefinition("viewResolver", new RootBeanDefinition(TestViewResolver.class)); RootBeanDefinition adapterDef = new RootBeanDefinition(RequestMappingHandlerMethodAdapter.class); adapterDef.getPropertyValues().add("webBindingInitializer", new MyWebBindingInitializer()); - adapterDef.getPropertyValues().add("customArgumentResolver", new MySpecialArgumentResolver()); + WebArgumentResolver[] argumentResolvers = new WebArgumentResolver[] {new MySpecialArgumentResolver()}; + adapterDef.getPropertyValues().add("customArgumentResolvers", argumentResolvers); wac.registerBeanDefinition("handlerAdapter", adapterDef); } }); @@ -1082,7 +1083,8 @@ public class ServletHandlerMethodTests { initDispatcherServlet(ModelAndViewResolverController.class, new BeanDefinitionRegistrar() { public void register(GenericWebApplicationContext wac) { RootBeanDefinition adapterDef = new RootBeanDefinition(RequestMappingHandlerMethodAdapter.class); - adapterDef.getPropertyValues().add("customModelAndViewResolver", new MyModelAndViewResolver()); + ModelAndViewResolver[] mavResolvers = new ModelAndViewResolver[] {new MyModelAndViewResolver()}; + adapterDef.getPropertyValues().add("customModelAndViewResolvers", mavResolvers); wac.registerBeanDefinition("handlerAdapter", adapterDef); } });