Consistent method selection for listeners and endpoint mappings
Issue: SPR-13654
This commit is contained in:
@@ -17,14 +17,9 @@
|
||||
package org.springframework.messaging.handler;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
import java.lang.reflect.Proxy;
|
||||
import java.util.Arrays;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.Set;
|
||||
|
||||
import org.springframework.core.BridgeMethodResolver;
|
||||
import org.springframework.util.ClassUtils;
|
||||
import org.springframework.util.ReflectionUtils;
|
||||
import org.springframework.core.MethodIntrospector;
|
||||
import org.springframework.util.ReflectionUtils.MethodFilter;
|
||||
|
||||
/**
|
||||
@@ -33,7 +28,9 @@ import org.springframework.util.ReflectionUtils.MethodFilter;
|
||||
*
|
||||
* @author Rossen Stoyanchev
|
||||
* @since 4.0
|
||||
* @deprecated as of Spring 4.2.3, in favor of the generalized and refined {@link MethodIntrospector}
|
||||
*/
|
||||
@Deprecated
|
||||
public abstract class HandlerMethodSelector {
|
||||
|
||||
/**
|
||||
@@ -42,31 +39,10 @@ public abstract class HandlerMethodSelector {
|
||||
* @param handlerType the handler type to search handler methods on
|
||||
* @param handlerMethodFilter a {@link MethodFilter} to help recognize handler methods of interest
|
||||
* @return the selected methods, or an empty set
|
||||
* @see MethodIntrospector#selectMethods(Class, MethodFilter)
|
||||
*/
|
||||
public static Set<Method> selectMethods(final Class<?> handlerType, final MethodFilter handlerMethodFilter) {
|
||||
final Set<Method> handlerMethods = new LinkedHashSet<Method>();
|
||||
Set<Class<?>> handlerTypes = new LinkedHashSet<Class<?>>();
|
||||
Class<?> specificHandlerType = null;
|
||||
if (!Proxy.isProxyClass(handlerType)) {
|
||||
handlerTypes.add(handlerType);
|
||||
specificHandlerType = handlerType;
|
||||
}
|
||||
handlerTypes.addAll(Arrays.asList(handlerType.getInterfaces()));
|
||||
for (Class<?> currentHandlerType : handlerTypes) {
|
||||
final Class<?> targetClass = (specificHandlerType != null ? specificHandlerType : currentHandlerType);
|
||||
ReflectionUtils.doWithMethods(currentHandlerType, new ReflectionUtils.MethodCallback() {
|
||||
@Override
|
||||
public void doWith(Method method) {
|
||||
Method specificMethod = ClassUtils.getMostSpecificMethod(method, targetClass);
|
||||
Method bridgedMethod = BridgeMethodResolver.findBridgedMethod(specificMethod);
|
||||
if (handlerMethodFilter.matches(specificMethod) &&
|
||||
(bridgedMethod == specificMethod || !handlerMethodFilter.matches(bridgedMethod))) {
|
||||
handlerMethods.add(specificMethod);
|
||||
}
|
||||
}
|
||||
}, ReflectionUtils.USER_DECLARED_METHODS);
|
||||
}
|
||||
return handlerMethods;
|
||||
public static Set<Method> selectMethods(Class<?> handlerType, MethodFilter handlerMethodFilter) {
|
||||
return MethodIntrospector.selectMethods(handlerType, handlerMethodFilter);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2013 the original author or authors.
|
||||
* Copyright 2002-2015 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.
|
||||
@@ -23,8 +23,8 @@ import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.springframework.core.MethodIntrospector;
|
||||
import org.springframework.core.annotation.AnnotationUtils;
|
||||
import org.springframework.messaging.handler.HandlerMethodSelector;
|
||||
import org.springframework.messaging.handler.annotation.MessageExceptionHandler;
|
||||
import org.springframework.messaging.handler.invocation.AbstractExceptionHandlerMethodResolver;
|
||||
import org.springframework.util.ReflectionUtils.MethodFilter;
|
||||
@@ -49,32 +49,39 @@ public class AnnotationExceptionHandlerMethodResolver extends AbstractExceptionH
|
||||
}
|
||||
|
||||
private static Map<Class<? extends Throwable>, Method> initExceptionMappings(Class<?> handlerType) {
|
||||
Map<Method, MessageExceptionHandler> methods = MethodIntrospector.selectMethods(handlerType,
|
||||
new MethodIntrospector.MetadataLookup<MessageExceptionHandler>() {
|
||||
@Override
|
||||
public MessageExceptionHandler inspect(Method method) {
|
||||
return AnnotationUtils.findAnnotation(method, MessageExceptionHandler.class);
|
||||
}
|
||||
});
|
||||
|
||||
Map<Class<? extends Throwable>, Method> result = new HashMap<Class<? extends Throwable>, Method>();
|
||||
for (Method method : HandlerMethodSelector.selectMethods(handlerType, EXCEPTION_HANDLER_METHOD_FILTER)) {
|
||||
for (Class<? extends Throwable> exceptionType : getMappedExceptions(method)) {
|
||||
for (Map.Entry<Method, MessageExceptionHandler> entry : methods.entrySet()) {
|
||||
Method method = entry.getKey();
|
||||
List<Class<? extends Throwable>> exceptionTypes = new ArrayList<Class<? extends Throwable>>();
|
||||
exceptionTypes.addAll(Arrays.asList(entry.getValue().value()));
|
||||
if (exceptionTypes.isEmpty()) {
|
||||
exceptionTypes.addAll(getExceptionsFromMethodSignature(method));
|
||||
}
|
||||
for (Class<? extends Throwable> exceptionType : exceptionTypes) {
|
||||
Method oldMethod = result.put(exceptionType, method);
|
||||
if (oldMethod != null && !oldMethod.equals(method)) {
|
||||
throw new IllegalStateException(
|
||||
"Ambiguous @ExceptionHandler method mapped for [" + exceptionType + "]: {" +
|
||||
oldMethod + ", " + method + "}.");
|
||||
throw new IllegalStateException("Ambiguous @ExceptionHandler method mapped for [" +
|
||||
exceptionType + "]: {" + oldMethod + ", " + method + "}");
|
||||
}
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
private static List<Class<? extends Throwable>> getMappedExceptions(Method method) {
|
||||
List<Class<? extends Throwable>> result = new ArrayList<Class<? extends Throwable>>();
|
||||
MessageExceptionHandler annot = AnnotationUtils.findAnnotation(method, MessageExceptionHandler.class);
|
||||
result.addAll(Arrays.asList(annot.value()));
|
||||
if (result.isEmpty()) {
|
||||
result.addAll(getExceptionsFromMethodSignature(method));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
/** A filter for selecting annotated exception handling methods. */
|
||||
/**
|
||||
* A filter for selecting annotated exception handling methods.
|
||||
* @deprecated as of Spring 4.2.3, since it isn't used anymore
|
||||
*/
|
||||
@Deprecated
|
||||
public final static MethodFilter EXCEPTION_HANDLER_METHOD_FILTER = new MethodFilter() {
|
||||
|
||||
@Override
|
||||
|
||||
@@ -34,20 +34,20 @@ import org.springframework.beans.factory.InitializingBean;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.context.ApplicationContextAware;
|
||||
import org.springframework.core.MethodParameter;
|
||||
import org.springframework.core.MethodIntrospector;
|
||||
import org.springframework.messaging.Message;
|
||||
import org.springframework.messaging.MessageHandler;
|
||||
import org.springframework.messaging.MessagingException;
|
||||
import org.springframework.messaging.handler.DestinationPatternsMessageCondition;
|
||||
import org.springframework.messaging.handler.HandlerMethod;
|
||||
import org.springframework.messaging.handler.HandlerMethodSelector;
|
||||
import org.springframework.messaging.handler.MessagingAdviceBean;
|
||||
import org.springframework.messaging.support.MessageBuilder;
|
||||
import org.springframework.messaging.support.MessageHeaderAccessor;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.ClassUtils;
|
||||
import org.springframework.util.CollectionUtils;
|
||||
import org.springframework.util.LinkedMultiValueMap;
|
||||
import org.springframework.util.MultiValueMap;
|
||||
import org.springframework.util.ReflectionUtils;
|
||||
import org.springframework.util.concurrent.ListenableFuture;
|
||||
import org.springframework.util.concurrent.ListenableFutureCallback;
|
||||
|
||||
@@ -60,6 +60,7 @@ import org.springframework.util.concurrent.ListenableFutureCallback;
|
||||
* exceptions raised during message handling.
|
||||
*
|
||||
* @author Rossen Stoyanchev
|
||||
* @author Juergen Hoeller
|
||||
* @since 4.0
|
||||
* @param <T> the type of the Object that contains information mapping a
|
||||
* {@link org.springframework.messaging.handler.HandlerMethod} to incoming messages
|
||||
@@ -250,22 +251,24 @@ public abstract class AbstractMethodMessageHandler<T>
|
||||
* so register it with the extracted mapping information.
|
||||
* @param handler the handler to check, either an instance of a Spring bean name
|
||||
*/
|
||||
protected final void detectHandlerMethods(Object handler) {
|
||||
protected final void detectHandlerMethods(final Object handler) {
|
||||
Class<?> handlerType = (handler instanceof String ?
|
||||
this.applicationContext.getType((String) handler) : handler.getClass());
|
||||
|
||||
final Class<?> userType = ClassUtils.getUserClass(handlerType);
|
||||
|
||||
Set<Method> methods = HandlerMethodSelector.selectMethods(userType, new ReflectionUtils.MethodFilter() {
|
||||
@Override
|
||||
public boolean matches(Method method) {
|
||||
return getMappingForMethod(method, userType) != null;
|
||||
}
|
||||
});
|
||||
Map<Method, T> methods = MethodIntrospector.selectMethods(userType,
|
||||
new MethodIntrospector.MetadataLookup<T>() {
|
||||
@Override
|
||||
public T inspect(Method method) {
|
||||
return getMappingForMethod(method, userType);
|
||||
}
|
||||
});
|
||||
|
||||
for (Method method : methods) {
|
||||
T mapping = getMappingForMethod(method, userType);
|
||||
registerHandlerMethod(handler, method, mapping);
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug(methods.size() + " message handler methods found on " + userType + ": " + methods);
|
||||
}
|
||||
for (Map.Entry<Method, T> entry : methods.entrySet()) {
|
||||
registerHandlerMethod(handler, entry.getKey(), entry.getValue());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -277,7 +280,6 @@ public abstract class AbstractMethodMessageHandler<T>
|
||||
*/
|
||||
protected abstract T getMappingForMethod(Method method, Class<?> handlerType);
|
||||
|
||||
|
||||
/**
|
||||
* Register a handler method and its unique mapping.
|
||||
* @param handler the bean name of the handler or the handler instance
|
||||
@@ -287,6 +289,7 @@ public abstract class AbstractMethodMessageHandler<T>
|
||||
* under the same mapping
|
||||
*/
|
||||
protected void registerHandlerMethod(Object handler, Method method, T mapping) {
|
||||
Assert.notNull(mapping, "Mapping must bot be null");
|
||||
HandlerMethod newHandlerMethod = createHandlerMethod(handler, method);
|
||||
HandlerMethod oldHandlerMethod = this.handlerMethods.get(mapping);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user