Resolve custom args after annotated args, set PATH_WITHIN_HANDLER_MAPPING attribute, and rename resolver for @ExceptionHandler methods

This commit is contained in:
Rossen Stoyanchev 2011-05-03 15:39:13 +00:00
parent 50117dce40
commit c91ab1ad6e
9 changed files with 74 additions and 82 deletions

View File

@ -42,7 +42,7 @@ import org.springframework.web.servlet.handler.ConversionServiceExposingIntercep
import org.springframework.web.servlet.handler.MappedInterceptor; import org.springframework.web.servlet.handler.MappedInterceptor;
import org.springframework.web.servlet.mvc.annotation.ResponseStatusExceptionResolver; import org.springframework.web.servlet.mvc.annotation.ResponseStatusExceptionResolver;
import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMethodAdapter; import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMethodAdapter;
import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMethodExceptionResolver; import org.springframework.web.servlet.mvc.method.annotation.ExceptionHandlerExceptionResolver;
import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMethodMapping; import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMethodMapping;
import org.springframework.web.servlet.mvc.support.DefaultHandlerExceptionResolver; import org.springframework.web.servlet.mvc.support.DefaultHandlerExceptionResolver;
@ -118,7 +118,7 @@ final class MvcAnnotationDrivenExecutor extends AbstractSpecificationExecutor<Mv
String mappedInterceptorName = registrar.registerWithGeneratedName(mappedCsInterceptorDef); String mappedInterceptorName = registrar.registerWithGeneratedName(mappedCsInterceptorDef);
RootBeanDefinition methodExceptionResolver = new RootBeanDefinition( RootBeanDefinition methodExceptionResolver = new RootBeanDefinition(
RequestMappingHandlerMethodExceptionResolver.class); ExceptionHandlerExceptionResolver.class);
methodExceptionResolver.setSource(source); methodExceptionResolver.setSource(source);
methodExceptionResolver.setRole(BeanDefinition.ROLE_INFRASTRUCTURE); methodExceptionResolver.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
methodExceptionResolver.getPropertyValues().add("messageConverters", messageConverters); methodExceptionResolver.getPropertyValues().add("messageConverters", messageConverters);

View File

@ -35,6 +35,7 @@ import org.springframework.util.MultiValueMap;
import org.springframework.util.ReflectionUtils.MethodFilter; import org.springframework.util.ReflectionUtils.MethodFilter;
import org.springframework.web.method.HandlerMethod; import org.springframework.web.method.HandlerMethod;
import org.springframework.web.method.HandlerMethodSelector; import org.springframework.web.method.HandlerMethodSelector;
import org.springframework.web.servlet.HandlerMapping;
import org.springframework.web.util.UrlPathHelper; import org.springframework.web.util.UrlPathHelper;
/** /**
@ -272,6 +273,7 @@ public abstract class AbstractHandlerMethodMapping<T> extends AbstractHandlerMap
* @param request the current request * @param request the current request
*/ */
protected void handleMatch(T mapping, String lookupPath, HttpServletRequest request) { protected void handleMatch(T mapping, String lookupPath, HttpServletRequest request) {
request.setAttribute(HandlerMapping.PATH_WITHIN_HANDLER_MAPPING_ATTRIBUTE, lookupPath);
} }
/** /**

View File

@ -79,7 +79,7 @@ import org.springframework.web.servlet.mvc.method.annotation.support.ViewMethodR
* @author Rossen Stoyanchev * @author Rossen Stoyanchev
* @since 3.1 * @since 3.1
*/ */
public class RequestMappingHandlerMethodExceptionResolver extends AbstractHandlerMethodExceptionResolver implements public class ExceptionHandlerExceptionResolver extends AbstractHandlerMethodExceptionResolver implements
InitializingBean { InitializingBean {
private List<HandlerMethodArgumentResolver> customArgumentResolvers; private List<HandlerMethodArgumentResolver> customArgumentResolvers;
@ -96,9 +96,9 @@ public class RequestMappingHandlerMethodExceptionResolver extends AbstractHandle
private HandlerMethodReturnValueHandlerComposite returnValueHandlers; private HandlerMethodReturnValueHandlerComposite returnValueHandlers;
/** /**
* Creates an instance of {@link RequestMappingHandlerMethodExceptionResolver}. * Creates an instance of {@link ExceptionHandlerExceptionResolver}.
*/ */
public RequestMappingHandlerMethodExceptionResolver() { public ExceptionHandlerExceptionResolver() {
StringHttpMessageConverter stringHttpMessageConverter = new StringHttpMessageConverter(); StringHttpMessageConverter stringHttpMessageConverter = new StringHttpMessageConverter();
stringHttpMessageConverter.setWriteAcceptCharset(false); // See SPR-7316 stringHttpMessageConverter.setWriteAcceptCharset(false); // See SPR-7316

View File

@ -331,95 +331,84 @@ public class RequestMappingHandlerMethodAdapter extends AbstractHandlerMethodAda
} }
public void afterPropertiesSet() throws Exception { public void afterPropertiesSet() throws Exception {
initArgumentResolvers();
initReturnValueHandlers();
initInitBinderArgumentResolvers();
}
private void initArgumentResolvers() {
if (argumentResolvers == null) { if (argumentResolvers == null) {
argumentResolvers = new HandlerMethodArgumentResolverComposite(); argumentResolvers = new HandlerMethodArgumentResolverComposite();
argumentResolvers.addResolvers(customArgumentResolvers);
argumentResolvers.addResolvers(getDefaultArgumentResolvers(messageConverters, beanFactory));
} }
if (returnValueHandlers == null) { // Annotation-based resolvers
returnValueHandlers = new HandlerMethodReturnValueHandlerComposite(); argumentResolvers.addResolver(new RequestParamMethodArgumentResolver(beanFactory, false));
returnValueHandlers.addHandlers(customReturnValueHandlers); argumentResolvers.addResolver(new RequestParamMapMethodArgumentResolver());
returnValueHandlers.addHandlers(getDefaultReturnValueHandlers(messageConverters, modelAndViewResolvers)); argumentResolvers.addResolver(new PathVariableMethodArgumentResolver());
} argumentResolvers.addResolver(new ServletModelAttributeMethodProcessor(false));
argumentResolvers.addResolver(new RequestResponseBodyMethodProcessor(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 ModelMethodProcessor());
argumentResolvers.addResolver(new ErrorsMethodArgumentResolver());
// Default-mode resolution
argumentResolvers.addResolver(new RequestParamMethodArgumentResolver(beanFactory, true));
argumentResolvers.addResolver(new ServletModelAttributeMethodProcessor(true));
}
private void initInitBinderArgumentResolvers() {
if (initBinderArgumentResolvers == null) { if (initBinderArgumentResolvers == null) {
initBinderArgumentResolvers = new HandlerMethodArgumentResolverComposite(); initBinderArgumentResolvers = new HandlerMethodArgumentResolverComposite();
initBinderArgumentResolvers.addResolvers(customArgumentResolvers);
initBinderArgumentResolvers.addResolvers(getDefaultInitBinderArgumentResolvers(beanFactory));
} }
}
public static List<HandlerMethodArgumentResolver> getDefaultArgumentResolvers(
List<HttpMessageConverter<?>> messageConverters, ConfigurableBeanFactory beanFactory) {
List<HandlerMethodArgumentResolver> resolvers = new ArrayList<HandlerMethodArgumentResolver>();
// Annotation-based resolvers // Annotation-based resolvers
resolvers.add(new RequestParamMethodArgumentResolver(beanFactory, false)); initBinderArgumentResolvers.addResolver(new RequestParamMethodArgumentResolver(beanFactory, false));
resolvers.add(new RequestParamMapMethodArgumentResolver()); initBinderArgumentResolvers.addResolver(new RequestParamMapMethodArgumentResolver());
resolvers.add(new PathVariableMethodArgumentResolver()); initBinderArgumentResolvers.addResolver(new PathVariableMethodArgumentResolver());
resolvers.add(new ServletModelAttributeMethodProcessor(false)); initBinderArgumentResolvers.addResolver(new ExpressionValueMethodArgumentResolver(beanFactory));
resolvers.add(new RequestResponseBodyMethodProcessor(messageConverters));
resolvers.add(new RequestHeaderMethodArgumentResolver(beanFactory)); // Custom resolvers
resolvers.add(new RequestHeaderMapMethodArgumentResolver()); argumentResolvers.addResolvers(customArgumentResolvers);
resolvers.add(new ServletCookieValueMethodArgumentResolver(beanFactory));
resolvers.add(new ExpressionValueMethodArgumentResolver(beanFactory));
// Type-based resolvers // Type-based resolvers
resolvers.add(new ServletRequestMethodArgumentResolver()); initBinderArgumentResolvers.addResolver(new ServletRequestMethodArgumentResolver());
resolvers.add(new ServletResponseMethodArgumentResolver()); initBinderArgumentResolvers.addResolver(new ServletResponseMethodArgumentResolver());
resolvers.add(new HttpEntityMethodProcessor(messageConverters));
resolvers.add(new ModelMethodProcessor());
resolvers.add(new ErrorsMethodArgumentResolver());
// Default-mode resolution // Default-mode resolution
resolvers.add(new RequestParamMethodArgumentResolver(beanFactory, true)); initBinderArgumentResolvers.addResolver(new RequestParamMethodArgumentResolver(beanFactory, true));
resolvers.add(new ServletModelAttributeMethodProcessor(true));
return resolvers;
}
public static List<HandlerMethodArgumentResolver> getDefaultInitBinderArgumentResolvers(
ConfigurableBeanFactory beanFactory) {
List<HandlerMethodArgumentResolver> resolvers = new ArrayList<HandlerMethodArgumentResolver>();
// Annotation-based resolvers
resolvers.add(new RequestParamMethodArgumentResolver(beanFactory, false));
resolvers.add(new RequestParamMapMethodArgumentResolver());
resolvers.add(new PathVariableMethodArgumentResolver());
resolvers.add(new ExpressionValueMethodArgumentResolver(beanFactory));
// Type-based resolvers
resolvers.add(new ServletRequestMethodArgumentResolver());
resolvers.add(new ServletResponseMethodArgumentResolver());
// Default-mode resolution
resolvers.add(new RequestParamMethodArgumentResolver(beanFactory, true));
return resolvers;
} }
public static List<HandlerMethodReturnValueHandler> getDefaultReturnValueHandlers( private void initReturnValueHandlers() {
List<HttpMessageConverter<?>> messageConverters, List<ModelAndViewResolver> modelAndViewResolvers) { if (returnValueHandlers == null) {
returnValueHandlers = new HandlerMethodReturnValueHandlerComposite();
List<HandlerMethodReturnValueHandler> handlers = new ArrayList<HandlerMethodReturnValueHandler>(); }
// Annotation-based handlers // Annotation-based handlers
handlers.add(new RequestResponseBodyMethodProcessor(messageConverters)); returnValueHandlers.addHandler(new RequestResponseBodyMethodProcessor(messageConverters));
handlers.add(new ModelAttributeMethodProcessor(false)); returnValueHandlers.addHandler(new ModelAttributeMethodProcessor(false));
// Custom return value handlers
returnValueHandlers.addHandlers(customReturnValueHandlers);
// Type-based handlers // Type-based handlers
handlers.add(new ModelAndViewMethodReturnValueHandler()); returnValueHandlers.addHandler(new ModelAndViewMethodReturnValueHandler());
handlers.add(new ModelMethodProcessor()); returnValueHandlers.addHandler(new ModelMethodProcessor());
handlers.add(new ViewMethodReturnValueHandler()); returnValueHandlers.addHandler(new ViewMethodReturnValueHandler());
handlers.add(new HttpEntityMethodProcessor(messageConverters)); returnValueHandlers.addHandler(new HttpEntityMethodProcessor(messageConverters));
// Default handler // Default handler
handlers.add(new DefaultMethodReturnValueHandler(modelAndViewResolvers)); returnValueHandlers.addHandler(new DefaultMethodReturnValueHandler(modelAndViewResolvers));
return handlers;
} }
@Override @Override

View File

@ -157,6 +157,7 @@ public class RequestMappingHandlerMethodMapping extends AbstractHandlerMethodMap
@Override @Override
protected void handleMatch(RequestMappingInfo mapping, String lookupPath, HttpServletRequest request) { protected void handleMatch(RequestMappingInfo mapping, String lookupPath, HttpServletRequest request) {
super.handleMatch(mapping, lookupPath, request);
String pattern = mapping.getPatterns().iterator().next(); String pattern = mapping.getPatterns().iterator().next();
Map<String, String> uriTemplateVariables = pathMatcher.extractUriTemplateVariables(pattern, lookupPath); Map<String, String> uriTemplateVariables = pathMatcher.extractUriTemplateVariables(pattern, lookupPath);
request.setAttribute(HandlerMapping.URI_TEMPLATE_VARIABLES_ATTRIBUTE, uriTemplateVariables); request.setAttribute(HandlerMapping.URI_TEMPLATE_VARIABLES_ATTRIBUTE, uriTemplateVariables);

View File

@ -39,7 +39,7 @@ import org.springframework.web.context.support.GenericWebApplicationContext;
import org.springframework.web.method.support.HandlerMethodArgumentResolver; import org.springframework.web.method.support.HandlerMethodArgumentResolver;
import org.springframework.web.method.support.ModelAndViewContainer; import org.springframework.web.method.support.ModelAndViewContainer;
import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMethodAdapter; import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMethodAdapter;
import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMethodExceptionResolver; import org.springframework.web.servlet.mvc.method.annotation.ExceptionHandlerExceptionResolver;
import org.springframework.web.servlet.mvc.method.annotation.support.ServletWebArgumentResolverAdapter; import org.springframework.web.servlet.mvc.method.annotation.support.ServletWebArgumentResolverAdapter;
/** /**
@ -71,14 +71,14 @@ public class AnnotationDrivenBeanDefinitionParserTests {
public void testMessageConverters() { public void testMessageConverters() {
loadBeanDefinitions("mvc-config-message-converters.xml"); loadBeanDefinitions("mvc-config-message-converters.xml");
verifyMessageConverters(appContext.getBean(RequestMappingHandlerMethodAdapter.class), true); verifyMessageConverters(appContext.getBean(RequestMappingHandlerMethodAdapter.class), true);
verifyMessageConverters(appContext.getBean(RequestMappingHandlerMethodExceptionResolver.class), true); verifyMessageConverters(appContext.getBean(ExceptionHandlerExceptionResolver.class), true);
} }
@Test @Test
public void testMessageConvertersWithoutDefaultRegistrations() { public void testMessageConvertersWithoutDefaultRegistrations() {
loadBeanDefinitions("mvc-config-message-converters-defaults-off.xml"); loadBeanDefinitions("mvc-config-message-converters-defaults-off.xml");
verifyMessageConverters(appContext.getBean(RequestMappingHandlerMethodAdapter.class), false); verifyMessageConverters(appContext.getBean(RequestMappingHandlerMethodAdapter.class), false);
verifyMessageConverters(appContext.getBean(RequestMappingHandlerMethodExceptionResolver.class), false); verifyMessageConverters(appContext.getBean(ExceptionHandlerExceptionResolver.class), false);
} }
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")

View File

@ -43,18 +43,18 @@ import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.web.method.HandlerMethod; import org.springframework.web.method.HandlerMethod;
import org.springframework.web.method.support.InvocableHandlerMethod; import org.springframework.web.method.support.InvocableHandlerMethod;
import org.springframework.web.servlet.ModelAndView; import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMethodExceptionResolver; import org.springframework.web.servlet.mvc.method.annotation.ExceptionHandlerExceptionResolver;
/** /**
* Test fixture with {@link RequestMappingHandlerMethodExceptionResolver}. * Test fixture with {@link ExceptionHandlerExceptionResolver}.
* *
* @author Rossen Stoyanchev * @author Rossen Stoyanchev
* @author Arjen Poutsma * @author Arjen Poutsma
* @since 3.1 * @since 3.1
*/ */
public class RequestMappingHandlerMethodExceptionResolverTests { public class ExceptionHandlerExceptionResolverTests {
private RequestMappingHandlerMethodExceptionResolver exceptionResolver; private ExceptionHandlerExceptionResolver exceptionResolver;
private MockHttpServletRequest request; private MockHttpServletRequest request;
@ -62,7 +62,7 @@ public class RequestMappingHandlerMethodExceptionResolverTests {
@Before @Before
public void setUp() throws Exception { public void setUp() throws Exception {
exceptionResolver = new RequestMappingHandlerMethodExceptionResolver(); exceptionResolver = new ExceptionHandlerExceptionResolver();
exceptionResolver.afterPropertiesSet(); exceptionResolver.afterPropertiesSet();
request = new MockHttpServletRequest(); request = new MockHttpServletRequest();
response = new MockHttpServletResponse(); response = new MockHttpServletResponse();

View File

@ -2636,7 +2636,7 @@ public class ServletHandlerMethodTests {
Class<?> adapterType = RequestMappingHandlerMethodAdapter.class; Class<?> adapterType = RequestMappingHandlerMethodAdapter.class;
wac.registerBeanDefinition("handlerAdapter", new RootBeanDefinition(adapterType)); wac.registerBeanDefinition("handlerAdapter", new RootBeanDefinition(adapterType));
Class<?> resolverType = RequestMappingHandlerMethodExceptionResolver.class; Class<?> resolverType = ExceptionHandlerExceptionResolver.class;
wac.registerBeanDefinition("requestMappingResolver", new RootBeanDefinition(resolverType)); wac.registerBeanDefinition("requestMappingResolver", new RootBeanDefinition(resolverType));
resolverType = ResponseStatusExceptionResolver.class; resolverType = ResponseStatusExceptionResolver.class;

View File

@ -607,7 +607,7 @@ public class UriTemplateServletHandlerMethodTests {
Class<?> adapterType = RequestMappingHandlerMethodAdapter.class; Class<?> adapterType = RequestMappingHandlerMethodAdapter.class;
wac.registerBeanDefinition("handlerAdapter", new RootBeanDefinition(adapterType)); wac.registerBeanDefinition("handlerAdapter", new RootBeanDefinition(adapterType));
Class<?> resolverType = RequestMappingHandlerMethodExceptionResolver.class; Class<?> resolverType = ExceptionHandlerExceptionResolver.class;
wac.registerBeanDefinition("requestMappingResolver", new RootBeanDefinition(resolverType)); wac.registerBeanDefinition("requestMappingResolver", new RootBeanDefinition(resolverType));
resolverType = ResponseStatusExceptionResolver.class; resolverType = ResponseStatusExceptionResolver.class;