Skip to content

Commit 981c894

Browse files
committed
@ExceptionHandler matches against cause type as well
Issue: SPR-14291
1 parent 99ae7e3 commit 981c894

File tree

4 files changed

+38
-21
lines changed

4 files changed

+38
-21
lines changed

spring-web/src/main/java/org/springframework/web/method/annotation/ExceptionHandlerMethodResolver.java

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2015 the original author or authors.
2+
* Copyright 2002-2016 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -31,14 +31,14 @@
3131
import org.springframework.util.ClassUtils;
3232
import org.springframework.util.ReflectionUtils.MethodFilter;
3333
import org.springframework.web.bind.annotation.ExceptionHandler;
34-
import org.springframework.web.util.NestedServletException;
3534

3635
/**
3736
* Discovers {@linkplain ExceptionHandler @ExceptionHandler} methods in a given class,
3837
* including all of its superclasses, and helps to resolve a given {@link Exception}
3938
* to the exception types supported by a given {@link Method}.
4039
*
4140
* @author Rossen Stoyanchev
41+
* @author Juergen Hoeller
4242
* @since 3.1
4343
*/
4444
public class ExceptionHandlerMethodResolver {
@@ -126,8 +126,11 @@ public boolean hasExceptionMappings() {
126126
*/
127127
public Method resolveMethod(Exception exception) {
128128
Method method = resolveMethodByExceptionType(exception.getClass());
129-
if (method == null && exception instanceof NestedServletException && exception.getCause() != null) {
130-
method = resolveMethodByExceptionType(exception.getCause().getClass());
129+
if (method == null) {
130+
Throwable cause = exception.getCause();
131+
if (cause != null) {
132+
method = resolveMethodByExceptionType(cause.getClass());
133+
}
131134
}
132135
return method;
133136
}

spring-webmvc/src/main/java/org/springframework/web/servlet/handler/AbstractHandlerMethodExceptionResolver.java

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2012 the original author or authors.
2+
* Copyright 2002-2016 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -34,7 +34,7 @@ public abstract class AbstractHandlerMethodExceptionResolver extends AbstractHan
3434

3535
/**
3636
* Checks if the handler is a {@link HandlerMethod} and then delegates to the
37-
* base class implementation of {@link #shouldApplyTo(HttpServletRequest, Object)}
37+
* base class implementation of {@code #shouldApplyTo(HttpServletRequest, Object)}
3838
* passing the bean of the {@code HandlerMethod}. Otherwise returns {@code false}.
3939
*/
4040
@Override
@@ -54,8 +54,7 @@ else if (handler instanceof HandlerMethod) {
5454

5555
@Override
5656
protected final ModelAndView doResolveException(
57-
HttpServletRequest request, HttpServletResponse response,
58-
Object handler, Exception ex) {
57+
HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) {
5958

6059
return doResolveHandlerMethodException(request, response, (HandlerMethod) handler, ex);
6160
}
@@ -75,7 +74,6 @@ protected final ModelAndView doResolveException(
7574
* @return a corresponding ModelAndView to forward to, or {@code null} for default processing
7675
*/
7776
protected abstract ModelAndView doResolveHandlerMethodException(
78-
HttpServletRequest request, HttpServletResponse response,
79-
HandlerMethod handlerMethod, Exception ex);
77+
HttpServletRequest request, HttpServletResponse response, HandlerMethod handlerMethod, Exception ex);
8078

8179
}

spring-webmvc/src/main/java/org/springframework/web/servlet/mvc/method/annotation/ExceptionHandlerExceptionResolver.java

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,7 @@
6565
* {@link #setArgumentResolvers} and {@link #setReturnValueHandlers(List)}.
6666
*
6767
* @author Rossen Stoyanchev
68+
* @author Juergen Hoeller
6869
* @since 3.1
6970
*/
7071
public class ExceptionHandlerExceptionResolver extends AbstractHandlerMethodExceptionResolver
@@ -364,10 +365,10 @@ protected ModelAndView doResolveHandlerMethodException(HttpServletRequest reques
364365
if (logger.isDebugEnabled()) {
365366
logger.debug("Invoking @ExceptionHandler method: " + exceptionHandlerMethod);
366367
}
367-
if (exception.getCause() != null) {
368-
// Expose root cause as provided argument as well
369-
exceptionHandlerMethod.invokeAndHandle(
370-
webRequest, mavContainer, exception, exception.getCause(), handlerMethod);
368+
Throwable cause = exception.getCause();
369+
if (cause != null) {
370+
// Expose cause as provided argument as well
371+
exceptionHandlerMethod.invokeAndHandle(webRequest, mavContainer, exception, cause, handlerMethod);
371372
}
372373
else {
373374
// Otherwise, just the given exception as-is

spring-webmvc/src/test/java/org/springframework/web/servlet/mvc/method/annotation/ExceptionHandlerExceptionResolverTests.java

Lines changed: 22 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
import org.junit.BeforeClass;
2626
import org.junit.Test;
2727

28+
import org.springframework.beans.FatalBeanException;
2829
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
2930
import org.springframework.context.annotation.Bean;
3031
import org.springframework.context.annotation.Configuration;
@@ -70,10 +71,10 @@ public class ExceptionHandlerExceptionResolverTests {
7071

7172
@BeforeClass
7273
public static void setupOnce() {
73-
ExceptionHandlerExceptionResolver r = new ExceptionHandlerExceptionResolver();
74-
r.afterPropertiesSet();
75-
RESOLVER_COUNT = r.getArgumentResolvers().getResolvers().size();
76-
HANDLER_COUNT = r.getReturnValueHandlers().getHandlers().size();
74+
ExceptionHandlerExceptionResolver resolver = new ExceptionHandlerExceptionResolver();
75+
resolver.afterPropertiesSet();
76+
RESOLVER_COUNT = resolver.getArgumentResolvers().getResolvers().size();
77+
HANDLER_COUNT = resolver.getReturnValueHandlers().getHandlers().size();
7778
}
7879

7980
@Before
@@ -220,9 +221,7 @@ public void resolveExceptionGlobalHandlerOrdered() throws Exception {
220221
assertEquals("TestExceptionResolver: IllegalStateException", this.response.getContentAsString());
221222
}
222223

223-
// SPR-12605
224-
225-
@Test
224+
@Test // SPR-12605
226225
public void resolveExceptionWithHandlerMethodArg() throws Exception {
227226
AnnotationConfigApplicationContext cxt = new AnnotationConfigApplicationContext(MyConfig.class);
228227
this.resolver.setApplicationContext(cxt);
@@ -253,6 +252,22 @@ public void resolveExceptionWithAssertionError() throws Exception {
253252
assertEquals(err.toString(), this.response.getContentAsString());
254253
}
255254

255+
@Test
256+
public void resolveExceptionWithAssertionErrorAsRootCause() throws Exception {
257+
AnnotationConfigApplicationContext cxt = new AnnotationConfigApplicationContext(MyConfig.class);
258+
this.resolver.setApplicationContext(cxt);
259+
this.resolver.afterPropertiesSet();
260+
261+
AssertionError err = new AssertionError("argh");
262+
FatalBeanException ex = new FatalBeanException("wrapped", err);
263+
HandlerMethod handlerMethod = new HandlerMethod(new ResponseBodyController(), "handle");
264+
ModelAndView mav = this.resolver.resolveException(this.request, this.response, handlerMethod, ex);
265+
266+
assertNotNull("Exception was not handled", mav);
267+
assertTrue(mav.isEmpty());
268+
assertEquals(err.toString(), this.response.getContentAsString());
269+
}
270+
256271
@Test
257272
public void resolveExceptionControllerAdviceHandler() throws Exception {
258273
AnnotationConfigApplicationContext cxt = new AnnotationConfigApplicationContext(MyControllerAdviceConfig.class);

0 commit comments

Comments
 (0)