001/* 002 * Copyright 2002-2018 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.AnnotatedElementUtils; 028import org.springframework.messaging.handler.annotation.MessageExceptionHandler; 029import org.springframework.messaging.handler.invocation.AbstractExceptionHandlerMethodResolver; 030 031/** 032 * A sub-class of {@link AbstractExceptionHandlerMethodResolver} that looks for 033 * {@link MessageExceptionHandler}-annotated methods in a given class. The actual 034 * exception types handled are extracted either from the annotation, if present, 035 * or from the method signature as a fallback option. 036 * 037 * @author Rossen Stoyanchev 038 * @author Juergen Hoeller 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 (MethodIntrospector.MetadataLookup<MessageExceptionHandler>) method -> 054 AnnotatedElementUtils.findMergedAnnotation(method, MessageExceptionHandler.class)); 055 056 Map<Class<? extends Throwable>, Method> result = new HashMap<>(); 057 for (Map.Entry<Method, MessageExceptionHandler> entry : methods.entrySet()) { 058 Method method = entry.getKey(); 059 List<Class<? extends Throwable>> exceptionTypes = new ArrayList<>(Arrays.asList(entry.getValue().value())); 060 if (exceptionTypes.isEmpty()) { 061 exceptionTypes.addAll(getExceptionsFromMethodSignature(method)); 062 } 063 for (Class<? extends Throwable> exceptionType : exceptionTypes) { 064 Method oldMethod = result.put(exceptionType, method); 065 if (oldMethod != null && !oldMethod.equals(method)) { 066 throw new IllegalStateException("Ambiguous @ExceptionHandler method mapped for [" + 067 exceptionType + "]: {" + oldMethod + ", " + method + "}"); 068 } 069 } 070 } 071 return result; 072 } 073 074}