|
|
|
@ -1,5 +1,5 @@ |
|
|
|
/* |
|
|
|
/* |
|
|
|
* Copyright 2002-2013 the original author or authors. |
|
|
|
* Copyright 2002-2014 the original author or authors. |
|
|
|
* |
|
|
|
* |
|
|
|
* Licensed under the Apache License, Version 2.0 (the "License"); |
|
|
|
* Licensed under the Apache License, Version 2.0 (the "License"); |
|
|
|
* you may not use this file except in compliance with the License. |
|
|
|
* you may not use this file except in compliance with the License. |
|
|
|
@ -28,7 +28,6 @@ import javax.servlet.http.HttpServletRequest; |
|
|
|
import javax.servlet.http.HttpServletResponse; |
|
|
|
import javax.servlet.http.HttpServletResponse; |
|
|
|
import javax.xml.transform.Source; |
|
|
|
import javax.xml.transform.Source; |
|
|
|
|
|
|
|
|
|
|
|
import org.springframework.beans.BeansException; |
|
|
|
|
|
|
|
import org.springframework.beans.factory.InitializingBean; |
|
|
|
import org.springframework.beans.factory.InitializingBean; |
|
|
|
import org.springframework.context.ApplicationContext; |
|
|
|
import org.springframework.context.ApplicationContext; |
|
|
|
import org.springframework.context.ApplicationContextAware; |
|
|
|
import org.springframework.context.ApplicationContextAware; |
|
|
|
@ -68,19 +67,24 @@ import org.springframework.web.servlet.handler.AbstractHandlerMethodExceptionRes |
|
|
|
* @author Rossen Stoyanchev |
|
|
|
* @author Rossen Stoyanchev |
|
|
|
* @since 3.1 |
|
|
|
* @since 3.1 |
|
|
|
*/ |
|
|
|
*/ |
|
|
|
public class ExceptionHandlerExceptionResolver extends AbstractHandlerMethodExceptionResolver implements |
|
|
|
public class ExceptionHandlerExceptionResolver extends AbstractHandlerMethodExceptionResolver |
|
|
|
InitializingBean, ApplicationContextAware { |
|
|
|
implements ApplicationContextAware, InitializingBean { |
|
|
|
|
|
|
|
|
|
|
|
private List<HandlerMethodArgumentResolver> customArgumentResolvers; |
|
|
|
private List<HandlerMethodArgumentResolver> customArgumentResolvers; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
private HandlerMethodArgumentResolverComposite argumentResolvers; |
|
|
|
|
|
|
|
|
|
|
|
private List<HandlerMethodReturnValueHandler> customReturnValueHandlers; |
|
|
|
private List<HandlerMethodReturnValueHandler> customReturnValueHandlers; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
private HandlerMethodReturnValueHandlerComposite returnValueHandlers; |
|
|
|
|
|
|
|
|
|
|
|
private List<HttpMessageConverter<?>> messageConverters; |
|
|
|
private List<HttpMessageConverter<?>> messageConverters; |
|
|
|
|
|
|
|
|
|
|
|
private ContentNegotiationManager contentNegotiationManager = new ContentNegotiationManager(); |
|
|
|
private ContentNegotiationManager contentNegotiationManager = new ContentNegotiationManager(); |
|
|
|
|
|
|
|
|
|
|
|
private final List<Object> responseBodyAdvice = new ArrayList<Object>(); |
|
|
|
private final List<Object> responseBodyAdvice = new ArrayList<Object>(); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
private ApplicationContext applicationContext; |
|
|
|
|
|
|
|
|
|
|
|
private final Map<Class<?>, ExceptionHandlerMethodResolver> exceptionHandlerCache = |
|
|
|
private final Map<Class<?>, ExceptionHandlerMethodResolver> exceptionHandlerCache = |
|
|
|
new ConcurrentHashMap<Class<?>, ExceptionHandlerMethodResolver>(64); |
|
|
|
new ConcurrentHashMap<Class<?>, ExceptionHandlerMethodResolver>(64); |
|
|
|
@ -88,17 +92,8 @@ public class ExceptionHandlerExceptionResolver extends AbstractHandlerMethodExce |
|
|
|
private final Map<ControllerAdviceBean, ExceptionHandlerMethodResolver> exceptionHandlerAdviceCache = |
|
|
|
private final Map<ControllerAdviceBean, ExceptionHandlerMethodResolver> exceptionHandlerAdviceCache = |
|
|
|
new LinkedHashMap<ControllerAdviceBean, ExceptionHandlerMethodResolver>(); |
|
|
|
new LinkedHashMap<ControllerAdviceBean, ExceptionHandlerMethodResolver>(); |
|
|
|
|
|
|
|
|
|
|
|
private HandlerMethodArgumentResolverComposite argumentResolvers; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
private HandlerMethodReturnValueHandlerComposite returnValueHandlers; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
private ApplicationContext applicationContext; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
|
|
|
* Default constructor. |
|
|
|
|
|
|
|
*/ |
|
|
|
|
|
|
|
public ExceptionHandlerExceptionResolver() { |
|
|
|
public ExceptionHandlerExceptionResolver() { |
|
|
|
|
|
|
|
|
|
|
|
StringHttpMessageConverter stringHttpMessageConverter = new StringHttpMessageConverter(); |
|
|
|
StringHttpMessageConverter stringHttpMessageConverter = new StringHttpMessageConverter(); |
|
|
|
stringHttpMessageConverter.setWriteAcceptCharset(false); // See SPR-7316
|
|
|
|
stringHttpMessageConverter.setWriteAcceptCharset(false); // See SPR-7316
|
|
|
|
|
|
|
|
|
|
|
|
@ -109,18 +104,6 @@ public class ExceptionHandlerExceptionResolver extends AbstractHandlerMethodExce |
|
|
|
this.messageConverters.add(new AllEncompassingFormHttpMessageConverter()); |
|
|
|
this.messageConverters.add(new AllEncompassingFormHttpMessageConverter()); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
|
|
|
* Add one or more components to be invoked after the execution of a controller |
|
|
|
|
|
|
|
* method annotated with {@code @ResponseBody} or returning {@code ResponseEntity} |
|
|
|
|
|
|
|
* but before the body is written to the response with the selected |
|
|
|
|
|
|
|
* {@code HttpMessageConverter}. |
|
|
|
|
|
|
|
*/ |
|
|
|
|
|
|
|
public void setResponseBodyAdvice(List<ResponseBodyAdvice<?>> responseBodyAdvice) { |
|
|
|
|
|
|
|
this.responseBodyAdvice.clear(); |
|
|
|
|
|
|
|
if (responseBodyAdvice != null) { |
|
|
|
|
|
|
|
this.responseBodyAdvice.addAll(responseBodyAdvice); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
/** |
|
|
|
* Provide resolvers for custom argument types. Custom resolvers are ordered |
|
|
|
* Provide resolvers for custom argument types. Custom resolvers are ordered |
|
|
|
@ -210,7 +193,7 @@ public class ExceptionHandlerExceptionResolver extends AbstractHandlerMethodExce |
|
|
|
* Return the configured message body converters. |
|
|
|
* Return the configured message body converters. |
|
|
|
*/ |
|
|
|
*/ |
|
|
|
public List<HttpMessageConverter<?>> getMessageConverters() { |
|
|
|
public List<HttpMessageConverter<?>> getMessageConverters() { |
|
|
|
return messageConverters; |
|
|
|
return this.messageConverters; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
/** |
|
|
|
@ -229,17 +212,20 @@ public class ExceptionHandlerExceptionResolver extends AbstractHandlerMethodExce |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
/** |
|
|
|
* Return an unmodifiable Map with the {@link ControllerAdvice @ControllerAdvice} |
|
|
|
* Add one or more components to be invoked after the execution of a controller |
|
|
|
* beans discovered in the ApplicationContext. The returned map will be empty if |
|
|
|
* method annotated with {@code @ResponseBody} or returning {@code ResponseEntity} |
|
|
|
* the method is invoked before the bean has been initialized via |
|
|
|
* but before the body is written to the response with the selected |
|
|
|
* {@link #afterPropertiesSet()}. |
|
|
|
* {@code HttpMessageConverter}. |
|
|
|
*/ |
|
|
|
*/ |
|
|
|
public Map<ControllerAdviceBean, ExceptionHandlerMethodResolver> getExceptionHandlerAdviceCache() { |
|
|
|
public void setResponseBodyAdvice(List<ResponseBodyAdvice<?>> responseBodyAdvice) { |
|
|
|
return Collections.unmodifiableMap(this.exceptionHandlerAdviceCache); |
|
|
|
this.responseBodyAdvice.clear(); |
|
|
|
|
|
|
|
if (responseBodyAdvice != null) { |
|
|
|
|
|
|
|
this.responseBodyAdvice.addAll(responseBodyAdvice); |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
@Override |
|
|
|
@Override |
|
|
|
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { |
|
|
|
public void setApplicationContext(ApplicationContext applicationContext) { |
|
|
|
this.applicationContext = applicationContext; |
|
|
|
this.applicationContext = applicationContext; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
@ -249,7 +235,6 @@ public class ExceptionHandlerExceptionResolver extends AbstractHandlerMethodExce |
|
|
|
|
|
|
|
|
|
|
|
@Override |
|
|
|
@Override |
|
|
|
public void afterPropertiesSet() { |
|
|
|
public void afterPropertiesSet() { |
|
|
|
|
|
|
|
|
|
|
|
// Do this first, it may add ResponseBodyAdvice beans
|
|
|
|
// Do this first, it may add ResponseBodyAdvice beans
|
|
|
|
initExceptionHandlerAdviceCache(); |
|
|
|
initExceptionHandlerAdviceCache(); |
|
|
|
|
|
|
|
|
|
|
|
@ -287,6 +272,16 @@ public class ExceptionHandlerExceptionResolver extends AbstractHandlerMethodExce |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
|
|
|
* Return an unmodifiable Map with the {@link ControllerAdvice @ControllerAdvice} |
|
|
|
|
|
|
|
* beans discovered in the ApplicationContext. The returned map will be empty if |
|
|
|
|
|
|
|
* the method is invoked before the bean has been initialized via |
|
|
|
|
|
|
|
* {@link #afterPropertiesSet()}. |
|
|
|
|
|
|
|
*/ |
|
|
|
|
|
|
|
public Map<ControllerAdviceBean, ExceptionHandlerMethodResolver> getExceptionHandlerAdviceCache() { |
|
|
|
|
|
|
|
return Collections.unmodifiableMap(this.exceptionHandlerAdviceCache); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
/** |
|
|
|
/** |
|
|
|
* Return the list of argument resolvers to use including built-in resolvers |
|
|
|
* Return the list of argument resolvers to use including built-in resolvers |
|
|
|
* and custom resolvers provided via {@link #setCustomArgumentResolvers}. |
|
|
|
* and custom resolvers provided via {@link #setCustomArgumentResolvers}. |
|
|
|
@ -365,7 +360,9 @@ public class ExceptionHandlerExceptionResolver extends AbstractHandlerMethodExce |
|
|
|
exceptionHandlerMethod.invokeAndHandle(webRequest, mavContainer, exception); |
|
|
|
exceptionHandlerMethod.invokeAndHandle(webRequest, mavContainer, exception); |
|
|
|
} |
|
|
|
} |
|
|
|
catch (Exception invocationEx) { |
|
|
|
catch (Exception invocationEx) { |
|
|
|
|
|
|
|
if (logger.isErrorEnabled()) { |
|
|
|
logger.error("Failed to invoke @ExceptionHandler method: " + exceptionHandlerMethod, invocationEx); |
|
|
|
logger.error("Failed to invoke @ExceptionHandler method: " + exceptionHandlerMethod, invocationEx); |
|
|
|
|
|
|
|
} |
|
|
|
return null; |
|
|
|
return null; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
@ -388,12 +385,13 @@ public class ExceptionHandlerExceptionResolver extends AbstractHandlerMethodExce |
|
|
|
* and if not found, it continues searching for additional {@code @ExceptionHandler} |
|
|
|
* and if not found, it continues searching for additional {@code @ExceptionHandler} |
|
|
|
* methods assuming some {@linkplain ControllerAdvice @ControllerAdvice} |
|
|
|
* methods assuming some {@linkplain ControllerAdvice @ControllerAdvice} |
|
|
|
* Spring-managed beans were detected. |
|
|
|
* Spring-managed beans were detected. |
|
|
|
* @param handlerMethod the method where the exception was raised, possibly {@code null} |
|
|
|
* @param handlerMethod the method where the exception was raised (may be {@code null}) |
|
|
|
* @param exception the raised exception |
|
|
|
* @param exception the raised exception |
|
|
|
* @return a method to handle the exception, or {@code null} |
|
|
|
* @return a method to handle the exception, or {@code null} |
|
|
|
*/ |
|
|
|
*/ |
|
|
|
protected ServletInvocableHandlerMethod getExceptionHandlerMethod(HandlerMethod handlerMethod, Exception exception) { |
|
|
|
protected ServletInvocableHandlerMethod getExceptionHandlerMethod(HandlerMethod handlerMethod, Exception exception) { |
|
|
|
Class<?> handlerType = (handlerMethod != null) ? handlerMethod.getBeanType() : null; |
|
|
|
Class<?> handlerType = (handlerMethod != null ? handlerMethod.getBeanType() : null); |
|
|
|
|
|
|
|
|
|
|
|
if (handlerMethod != null) { |
|
|
|
if (handlerMethod != null) { |
|
|
|
ExceptionHandlerMethodResolver resolver = this.exceptionHandlerCache.get(handlerType); |
|
|
|
ExceptionHandlerMethodResolver resolver = this.exceptionHandlerCache.get(handlerType); |
|
|
|
if (resolver == null) { |
|
|
|
if (resolver == null) { |
|
|
|
@ -405,6 +403,7 @@ public class ExceptionHandlerExceptionResolver extends AbstractHandlerMethodExce |
|
|
|
return new ServletInvocableHandlerMethod(handlerMethod.getBean(), method); |
|
|
|
return new ServletInvocableHandlerMethod(handlerMethod.getBean(), method); |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
for (Entry<ControllerAdviceBean, ExceptionHandlerMethodResolver> entry : this.exceptionHandlerAdviceCache.entrySet()) { |
|
|
|
for (Entry<ControllerAdviceBean, ExceptionHandlerMethodResolver> entry : this.exceptionHandlerAdviceCache.entrySet()) { |
|
|
|
if (entry.getKey().isApplicableToBeanType(handlerType)) { |
|
|
|
if (entry.getKey().isApplicableToBeanType(handlerType)) { |
|
|
|
ExceptionHandlerMethodResolver resolver = entry.getValue(); |
|
|
|
ExceptionHandlerMethodResolver resolver = entry.getValue(); |
|
|
|
@ -414,6 +413,7 @@ public class ExceptionHandlerExceptionResolver extends AbstractHandlerMethodExce |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
return null; |
|
|
|
return null; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|