001/* 002 * Copyright 2002-2015 the original author or authors. 003 * 004 * Licensed under the Apache License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * https://www.apache.org/licenses/LICENSE-2.0 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 */ 016 017package org.springframework.messaging.handler.annotation.support; 018 019import java.lang.reflect.Method; 020import java.util.ArrayList; 021import java.util.Arrays; 022import java.util.HashMap; 023import java.util.List; 024import java.util.Map; 025 026import org.springframework.core.MethodIntrospector; 027import org.springframework.core.annotation.AnnotationUtils; 028import org.springframework.messaging.handler.annotation.MessageExceptionHandler; 029import org.springframework.messaging.handler.invocation.AbstractExceptionHandlerMethodResolver; 030import org.springframework.util.ReflectionUtils.MethodFilter; 031 032/** 033 * A sub-class of {@link AbstractExceptionHandlerMethodResolver} that looks for 034 * {@link MessageExceptionHandler}-annotated methods in a given class. The actual 035 * exception types handled are extracted either from the annotation, if present, 036 * or from the method signature as a fallback option. 037 * 038 * @author Rossen Stoyanchev 039 * @since 4.0 040 */ 041public class AnnotationExceptionHandlerMethodResolver extends AbstractExceptionHandlerMethodResolver { 042 043 /** 044 * A constructor that finds {@link MessageExceptionHandler} methods in the given type. 045 * @param handlerType the type to introspect 046 */ 047 public AnnotationExceptionHandlerMethodResolver(Class<?> handlerType) { 048 super(initExceptionMappings(handlerType)); 049 } 050 051 private static Map<Class<? extends Throwable>, Method> initExceptionMappings(Class<?> handlerType) { 052 Map<Method, MessageExceptionHandler> methods = MethodIntrospector.selectMethods(handlerType, 053 new MethodIntrospector.MetadataLookup<MessageExceptionHandler>() { 054 @Override 055 public MessageExceptionHandler inspect(Method method) { 056 return AnnotationUtils.findAnnotation(method, MessageExceptionHandler.class); 057 } 058 }); 059 060 Map<Class<? extends Throwable>, Method> result = new HashMap<Class<? extends Throwable>, Method>(); 061 for (Map.Entry<Method, MessageExceptionHandler> entry : methods.entrySet()) { 062 Method method = entry.getKey(); 063 List<Class<? extends Throwable>> exceptionTypes = new ArrayList<Class<? extends Throwable>>(); 064 exceptionTypes.addAll(Arrays.asList(entry.getValue().value())); 065 if (exceptionTypes.isEmpty()) { 066 exceptionTypes.addAll(getExceptionsFromMethodSignature(method)); 067 } 068 for (Class<? extends Throwable> exceptionType : exceptionTypes) { 069 Method oldMethod = result.put(exceptionType, method); 070 if (oldMethod != null && !oldMethod.equals(method)) { 071 throw new IllegalStateException("Ambiguous @ExceptionHandler method mapped for [" + 072 exceptionType + "]: {" + oldMethod + ", " + method + "}"); 073 } 074 } 075 } 076 return result; 077 } 078 079 080 /** 081 * A filter for selecting annotated exception handling methods. 082 * @deprecated as of Spring 4.2.3, since it isn't used anymore 083 */ 084 @Deprecated 085 public final static MethodFilter EXCEPTION_HANDLER_METHOD_FILTER = new MethodFilter() { 086 087 @Override 088 public boolean matches(Method method) { 089 return AnnotationUtils.findAnnotation(method, MessageExceptionHandler.class) != null; 090 } 091 }; 092 093}