diff --git a/spring-messaging/src/main/java/org/springframework/messaging/handler/invocation/AbstractExceptionHandlerMethodResolver.java b/spring-messaging/src/main/java/org/springframework/messaging/handler/invocation/AbstractExceptionHandlerMethodResolver.java index b2851730685..a7f7cf9f560 100644 --- a/spring-messaging/src/main/java/org/springframework/messaging/handler/invocation/AbstractExceptionHandlerMethodResolver.java +++ b/spring-messaging/src/main/java/org/springframework/messaging/handler/invocation/AbstractExceptionHandlerMethodResolver.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2013 the original author or authors. + * Copyright 2002-2016 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. @@ -33,6 +33,7 @@ import org.springframework.util.ClassUtils; * {@link ExceptionDepthComparator} and the top match is returned. * * @author Rossen Stoyanchev + * @author Juergen Hoeller * @since 4.0 */ public abstract class AbstractExceptionHandlerMethodResolver { @@ -69,6 +70,7 @@ public abstract class AbstractExceptionHandlerMethodResolver { return result; } + /** * Whether the contained type has any exception mappings. */ @@ -77,13 +79,30 @@ public abstract class AbstractExceptionHandlerMethodResolver { } /** - * Find a method to handle the given exception. - * Use {@link org.springframework.core.ExceptionDepthComparator} if more than one match is found. + * Find a {@link Method} to handle the given exception. + * Use {@link ExceptionDepthComparator} if more than one match is found. * @param exception the exception - * @return a method to handle the exception or {@code null} + * @return a Method to handle the exception, or {@code null} if none found */ public Method resolveMethod(Exception exception) { - Class exceptionType = exception.getClass(); + Method method = resolveMethodByExceptionType(exception.getClass()); + if (method == null) { + Throwable cause = exception.getCause(); + if (cause != null) { + method = resolveMethodByExceptionType(cause.getClass()); + } + } + return method; + } + + /** + * Find a {@link Method} to handle the given exception type. This can be + * useful if an {@link Exception} instance is not available (e.g. for tools). + * @param exceptionType the exception type + * @return a Method to handle the exception, or {@code null} if none found + * @since 4.3.1 + */ + public Method resolveMethodByExceptionType(Class exceptionType) { Method method = this.exceptionLookupCache.get(exceptionType); if (method == null) { method = getMappedMethod(exceptionType); @@ -93,9 +112,9 @@ public abstract class AbstractExceptionHandlerMethodResolver { } /** - * Return the method mapped to the given exception type or {@code null}. + * Return the {@link Method} mapped to the given exception type, or {@code null} if none. */ - private Method getMappedMethod(Class exceptionType) { + private Method getMappedMethod(Class exceptionType) { List> matches = new ArrayList>(); for (Class mappedException : this.mappedMethods.keySet()) { if (mappedException.isAssignableFrom(exceptionType)) { diff --git a/spring-messaging/src/test/java/org/springframework/messaging/handler/annotation/support/AnnotationExceptionHandlerMethodResolverTests.java b/spring-messaging/src/test/java/org/springframework/messaging/handler/annotation/support/AnnotationExceptionHandlerMethodResolverTests.java index e63673e08c3..2966a290c6f 100644 --- a/spring-messaging/src/test/java/org/springframework/messaging/handler/annotation/support/AnnotationExceptionHandlerMethodResolverTests.java +++ b/spring-messaging/src/test/java/org/springframework/messaging/handler/annotation/support/AnnotationExceptionHandlerMethodResolverTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2013 the original author or authors. + * Copyright 2002-2016 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. @@ -33,6 +33,7 @@ import static org.junit.Assert.*; * Test fixture for {@link AnnotationExceptionHandlerMethodResolver} tests. * * @author Rossen Stoyanchev + * @author Juergen Hoeller */ public class AnnotationExceptionHandlerMethodResolverTests { @@ -50,6 +51,13 @@ public class AnnotationExceptionHandlerMethodResolverTests { assertEquals("handleIllegalArgumentException", resolver.resolveMethod(exception).getName()); } + @Test + public void resolveMethodFromArgumentWithErrorType() { + AnnotationExceptionHandlerMethodResolver resolver = new AnnotationExceptionHandlerMethodResolver(ExceptionController.class); + AssertionError exception = new AssertionError(); + assertEquals("handleAssertionError", resolver.resolveMethod(new IllegalStateException(exception)).getName()); + } + @Test public void resolveMethodExceptionSubType() { AnnotationExceptionHandlerMethodResolver resolver = new AnnotationExceptionHandlerMethodResolver(ExceptionController.class); @@ -91,6 +99,7 @@ public class AnnotationExceptionHandlerMethodResolverTests { new AnnotationExceptionHandlerMethodResolver(NoExceptionController.class); } + @Controller static class ExceptionController { @@ -107,8 +116,13 @@ public class AnnotationExceptionHandlerMethodResolverTests { @MessageExceptionHandler public void handleIllegalArgumentException(IllegalArgumentException exception) { } + + @MessageExceptionHandler + public void handleAssertionError(AssertionError exception) { + } } + @Controller static class InheritedController extends ExceptionController { @@ -117,6 +131,7 @@ public class AnnotationExceptionHandlerMethodResolverTests { } } + @Controller static class AmbiguousController { @@ -133,6 +148,7 @@ public class AnnotationExceptionHandlerMethodResolverTests { } } + @Controller static class NoExceptionController {