Explicit coverage of root vs cause exception matching in MVC ref docs

Issue: SPR-16743

(cherry picked from commit a200df6)
This commit is contained in:
Juergen Hoeller
2018-05-07 22:30:26 +02:00
parent d9ff109b0f
commit 318d04cd2b
3 changed files with 83 additions and 100 deletions

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2017 the original author or authors.
* Copyright 2002-2018 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.
@@ -25,7 +25,6 @@ import org.springframework.beans.factory.FactoryBean;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.config.BeanDefinitionHolder;
import org.springframework.beans.factory.config.BeanReference;
import org.springframework.beans.factory.config.RuntimeBeanReference;
import org.springframework.beans.factory.parsing.BeanComponentDefinition;
import org.springframework.beans.factory.parsing.CompositeComponentDefinition;
@@ -53,13 +52,10 @@ import org.springframework.http.converter.xml.Jaxb2RootElementHttpMessageConvert
import org.springframework.http.converter.xml.MappingJackson2XmlHttpMessageConverter;
import org.springframework.http.converter.xml.SourceHttpMessageConverter;
import org.springframework.util.ClassUtils;
import org.springframework.util.StringUtils;
import org.springframework.util.xml.DomUtils;
import org.springframework.web.HttpRequestHandler;
import org.springframework.web.accept.ContentNegotiationManager;
import org.springframework.web.accept.ContentNegotiationManagerFactoryBean;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.web.bind.support.ConfigurableWebBindingInitializer;
import org.springframework.web.bind.support.WebArgumentResolver;
import org.springframework.web.method.support.CompositeUriComponentsContributor;
@@ -110,10 +106,10 @@ import org.springframework.web.servlet.mvc.support.DefaultHandlerExceptionResolv
*
* <p>This class registers the following {@link HandlerExceptionResolver}s:
* <ul>
* <li>{@link ExceptionHandlerExceptionResolver} for handling exceptions
* through @{@link ExceptionHandler} methods.
* <li>{@link ExceptionHandlerExceptionResolver} for handling exceptions through
* {@link org.springframework.web.bind.annotation.ExceptionHandler} methods.
* <li>{@link ResponseStatusExceptionResolver} for exceptions annotated
* with @{@link ResponseStatus}.
* with {@link org.springframework.web.bind.annotation.ResponseStatus}.
* <li>{@link DefaultHandlerExceptionResolver} for resolving known Spring
* exception types
* </ul>
@@ -155,6 +151,7 @@ class AnnotationDrivenBeanDefinitionParser implements BeanDefinitionParser {
public static final String CONTENT_NEGOTIATION_MANAGER_BEAN_NAME = "mvcContentNegotiationManager";
private static final boolean javaxValidationPresent =
ClassUtils.isPresent("javax.validation.Validator",
AnnotationDrivenBeanDefinitionParser.class.getClassLoader());
@@ -210,8 +207,8 @@ class AnnotationDrivenBeanDefinitionParser implements BeanDefinitionParser {
configurePathMatchingProperties(handlerMappingDef, element, parserContext);
readerContext.getRegistry().registerBeanDefinition(HANDLER_MAPPING_BEAN_NAME , handlerMappingDef);
RuntimeBeanReference corsConfigurationsRef = MvcNamespaceUtils.registerCorsConfigurations(null, parserContext, source);
handlerMappingDef.getPropertyValues().add("corsConfigurations", corsConfigurationsRef);
RuntimeBeanReference corsRef = MvcNamespaceUtils.registerCorsConfigurations(null, parserContext, source);
handlerMappingDef.getPropertyValues().add("corsConfigurations", corsRef);
RuntimeBeanReference conversionService = getConversionService(element, source, parserContext);
RuntimeBeanReference validator = getValidator(element, source, parserContext);
@@ -285,44 +282,40 @@ class AnnotationDrivenBeanDefinitionParser implements BeanDefinitionParser {
mappedCsInterceptorDef.getConstructorArgumentValues().addIndexedArgumentValue(1, csInterceptorDef);
String mappedInterceptorName = readerContext.registerWithGeneratedName(mappedCsInterceptorDef);
RootBeanDefinition exceptionHandlerExceptionResolver = new RootBeanDefinition(ExceptionHandlerExceptionResolver.class);
exceptionHandlerExceptionResolver.setSource(source);
exceptionHandlerExceptionResolver.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
exceptionHandlerExceptionResolver.getPropertyValues().add("contentNegotiationManager", contentNegotiationManager);
exceptionHandlerExceptionResolver.getPropertyValues().add("messageConverters", messageConverters);
exceptionHandlerExceptionResolver.getPropertyValues().add("order", 0);
addResponseBodyAdvice(exceptionHandlerExceptionResolver);
RootBeanDefinition methodExceptionResolver = new RootBeanDefinition(ExceptionHandlerExceptionResolver.class);
methodExceptionResolver.setSource(source);
methodExceptionResolver.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
methodExceptionResolver.getPropertyValues().add("contentNegotiationManager", contentNegotiationManager);
methodExceptionResolver.getPropertyValues().add("messageConverters", messageConverters);
methodExceptionResolver.getPropertyValues().add("order", 0);
addResponseBodyAdvice(methodExceptionResolver);
if (argumentResolvers != null) {
exceptionHandlerExceptionResolver.getPropertyValues().add("customArgumentResolvers", argumentResolvers);
methodExceptionResolver.getPropertyValues().add("customArgumentResolvers", argumentResolvers);
}
if (returnValueHandlers != null) {
exceptionHandlerExceptionResolver.getPropertyValues().add("customReturnValueHandlers", returnValueHandlers);
methodExceptionResolver.getPropertyValues().add("customReturnValueHandlers", returnValueHandlers);
}
String methodExResolverName = readerContext.registerWithGeneratedName(methodExceptionResolver);
String methodExceptionResolverName = readerContext.registerWithGeneratedName(exceptionHandlerExceptionResolver);
RootBeanDefinition responseStatusExceptionResolver = new RootBeanDefinition(ResponseStatusExceptionResolver.class);
responseStatusExceptionResolver.setSource(source);
responseStatusExceptionResolver.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
responseStatusExceptionResolver.getPropertyValues().add("order", 1);
String responseStatusExceptionResolverName =
readerContext.registerWithGeneratedName(responseStatusExceptionResolver);
RootBeanDefinition statusExceptionResolver = new RootBeanDefinition(ResponseStatusExceptionResolver.class);
statusExceptionResolver.setSource(source);
statusExceptionResolver.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
statusExceptionResolver.getPropertyValues().add("order", 1);
String statusExResolverName = readerContext.registerWithGeneratedName(statusExceptionResolver);
RootBeanDefinition defaultExceptionResolver = new RootBeanDefinition(DefaultHandlerExceptionResolver.class);
defaultExceptionResolver.setSource(source);
defaultExceptionResolver.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
defaultExceptionResolver.getPropertyValues().add("order", 2);
String defaultExceptionResolverName =
readerContext.registerWithGeneratedName(defaultExceptionResolver);
String defaultExResolverName = readerContext.registerWithGeneratedName(defaultExceptionResolver);
parserContext.registerComponent(new BeanComponentDefinition(handlerMappingDef, HANDLER_MAPPING_BEAN_NAME));
parserContext.registerComponent(new BeanComponentDefinition(handlerAdapterDef, HANDLER_ADAPTER_BEAN_NAME));
parserContext.registerComponent(new BeanComponentDefinition(uriCompContribDef, uriCompContribName));
parserContext.registerComponent(new BeanComponentDefinition(exceptionHandlerExceptionResolver, methodExceptionResolverName));
parserContext.registerComponent(new BeanComponentDefinition(responseStatusExceptionResolver, responseStatusExceptionResolverName));
parserContext.registerComponent(new BeanComponentDefinition(defaultExceptionResolver, defaultExceptionResolverName));
parserContext.registerComponent(new BeanComponentDefinition(mappedCsInterceptorDef, mappedInterceptorName));
parserContext.registerComponent(new BeanComponentDefinition(uriContributorDef, uriContributorName));
parserContext.registerComponent(new BeanComponentDefinition(mappedInterceptorDef, mappedInterceptorName));
parserContext.registerComponent(new BeanComponentDefinition(methodExceptionResolver, methodExResolverName));
parserContext.registerComponent(new BeanComponentDefinition(statusExceptionResolver, statusExResolverName));
parserContext.registerComponent(new BeanComponentDefinition(defaultExceptionResolver, defaultExResolverName));
// Ensure BeanNameUrlHandlerMapping (SPR-8289) and default HandlerAdapters are not "turned off"
MvcNamespaceUtils.registerDefaultComponents(parserContext, source);
@@ -380,8 +373,8 @@ class AnnotationDrivenBeanDefinitionParser implements BeanDefinitionParser {
}
}
private RuntimeBeanReference getContentNegotiationManager(Element element, Object source,
ParserContext parserContext) {
private RuntimeBeanReference getContentNegotiationManager(
Element element, Object source, ParserContext parserContext) {
RuntimeBeanReference beanRef;
if (element.hasAttribute("content-negotiation-manager")) {
@@ -402,8 +395,8 @@ class AnnotationDrivenBeanDefinitionParser implements BeanDefinitionParser {
return beanRef;
}
private void configurePathMatchingProperties(RootBeanDefinition handlerMappingDef, Element element,
ParserContext parserContext) {
private void configurePathMatchingProperties(
RootBeanDefinition handlerMappingDef, Element element, ParserContext parserContext) {
Element pathMatchingElement = DomUtils.getChildElementByTagName(element, "path-matching");
if (pathMatchingElement != null) {
@@ -462,15 +455,13 @@ class AnnotationDrivenBeanDefinitionParser implements BeanDefinitionParser {
private String getAsyncTimeout(Element element) {
Element asyncElement = DomUtils.getChildElementByTagName(element, "async-support");
return (asyncElement != null) ? asyncElement.getAttribute("default-timeout") : null;
return (asyncElement != null ? asyncElement.getAttribute("default-timeout") : null);
}
private RuntimeBeanReference getAsyncExecutor(Element element) {
Element asyncElement = DomUtils.getChildElementByTagName(element, "async-support");
if (asyncElement != null) {
if (asyncElement.hasAttribute("task-executor")) {
return new RuntimeBeanReference(asyncElement.getAttribute("task-executor"));
}
if (asyncElement != null && asyncElement.hasAttribute("task-executor")) {
return new RuntimeBeanReference(asyncElement.getAttribute("task-executor"));
}
return null;
}
@@ -571,7 +562,8 @@ class AnnotationDrivenBeanDefinitionParser implements BeanDefinitionParser {
}
if (jackson2XmlPresent) {
RootBeanDefinition jacksonConverterDef = createConverterDefinition(MappingJackson2XmlHttpMessageConverter.class, source);
Class<?> type = MappingJackson2XmlHttpMessageConverter.class;
RootBeanDefinition jacksonConverterDef = createConverterDefinition(type, source);
GenericBeanDefinition jacksonFactoryDef = createObjectMapperFactoryDefinition(source);
jacksonFactoryDef.getPropertyValues().add("createXmlMapper", true);
jacksonConverterDef.getConstructorArgumentValues().addIndexedArgumentValue(0, jacksonFactoryDef);
@@ -582,7 +574,8 @@ class AnnotationDrivenBeanDefinitionParser implements BeanDefinitionParser {
}
if (jackson2Present) {
RootBeanDefinition jacksonConverterDef = createConverterDefinition(MappingJackson2HttpMessageConverter.class, source);
Class<?> type = MappingJackson2HttpMessageConverter.class;
RootBeanDefinition jacksonConverterDef = createConverterDefinition(type, source);
GenericBeanDefinition jacksonFactoryDef = createObjectMapperFactoryDefinition(source);
jacksonConverterDef.getConstructorArgumentValues().addIndexedArgumentValue(0, jacksonFactoryDef);
messageConverters.add(jacksonConverterDef);
@@ -609,7 +602,6 @@ class AnnotationDrivenBeanDefinitionParser implements BeanDefinitionParser {
return beanDefinition;
}
private ManagedList<Object> extractBeanSubElements(Element parentElement, ParserContext parserContext) {
ManagedList<Object> list = new ManagedList<Object>();
list.setSource(parserContext.extractSource(parentElement));
@@ -620,27 +612,6 @@ class AnnotationDrivenBeanDefinitionParser implements BeanDefinitionParser {
return list;
}
private ManagedList<BeanReference> extractBeanRefSubElements(Element parentElement, ParserContext parserContext){
ManagedList<BeanReference> list = new ManagedList<BeanReference>();
list.setSource(parserContext.extractSource(parentElement));
for (Element refElement : DomUtils.getChildElementsByTagName(parentElement, "ref")) {
BeanReference reference;
if (StringUtils.hasText("bean")) {
reference = new RuntimeBeanReference(refElement.getAttribute("bean"),false);
list.add(reference);
}
else if (StringUtils.hasText("parent")){
reference = new RuntimeBeanReference(refElement.getAttribute("parent"),true);
list.add(reference);
}
else {
parserContext.getReaderContext().error("'bean' or 'parent' attribute is required for <ref> element",
parserContext.extractSource(parentElement));
}
}
return list;
}
/**
* A FactoryBean for a CompositeUriComponentsContributor that obtains the
@@ -671,7 +642,7 @@ class AnnotationDrivenBeanDefinitionParser implements BeanDefinitionParser {
}
@Override
public CompositeUriComponentsContributor getObject() throws Exception {
public CompositeUriComponentsContributor getObject() {
return this.uriComponentsContributor;
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2017 the original author or authors.
* Copyright 2002-2018 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.
@@ -63,8 +63,6 @@ import org.springframework.validation.Validator;
import org.springframework.web.HttpRequestHandler;
import org.springframework.web.accept.ContentNegotiationManager;
import org.springframework.web.bind.WebDataBinder;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.web.bind.support.ConfigurableWebBindingInitializer;
import org.springframework.web.context.ServletContextAware;
import org.springframework.web.cors.CorsConfiguration;
@@ -134,10 +132,10 @@ import org.springframework.web.util.UrlPathHelper;
* <p>Registers a {@link HandlerExceptionResolverComposite} with this chain of
* exception resolvers:
* <ul>
* <li>{@link ExceptionHandlerExceptionResolver} for handling exceptions
* through @{@link ExceptionHandler} methods.
* <li>{@link ResponseStatusExceptionResolver} for exceptions annotated
* with @{@link ResponseStatus}.
* <li>{@link ExceptionHandlerExceptionResolver} for handling exceptions through
* {@link org.springframework.web.bind.annotation.ExceptionHandler} methods.
* <li>{@link ResponseStatusExceptionResolver} for exceptions annotated with
* {@link org.springframework.web.bind.annotation.ResponseStatus}.
* <li>{@link DefaultHandlerExceptionResolver} for resolving known Spring
* exception types
* </ul>
@@ -865,12 +863,11 @@ public class WebMvcConfigurationSupport implements ApplicationContextAware, Serv
* A method available to subclasses for adding default {@link HandlerExceptionResolver}s.
* <p>Adds the following exception resolvers:
* <ul>
* <li>{@link ExceptionHandlerExceptionResolver}
* for handling exceptions through @{@link ExceptionHandler} methods.
* <li>{@link ResponseStatusExceptionResolver}
* for exceptions annotated with @{@link ResponseStatus}.
* <li>{@link DefaultHandlerExceptionResolver}
* for resolving known Spring exception types
* <li>{@link ExceptionHandlerExceptionResolver} for handling exceptions through
* {@link org.springframework.web.bind.annotation.ExceptionHandler} methods.
* <li>{@link ResponseStatusExceptionResolver} for exceptions annotated with
* {@link org.springframework.web.bind.annotation.ResponseStatus}.
* <li>{@link DefaultHandlerExceptionResolver} for resolving known Spring exception types
* </ul>
*/
protected final void addDefaultHandlerExceptionResolvers(List<HandlerExceptionResolver> exceptionResolvers) {