diff --git a/spring-core/src/main/java/org/springframework/core/MethodIntrospector.java b/spring-core/src/main/java/org/springframework/core/MethodIntrospector.java
new file mode 100644
index 0000000000..d402c10b6d
--- /dev/null
+++ b/spring-core/src/main/java/org/springframework/core/MethodIntrospector.java
@@ -0,0 +1,157 @@
+/*
+ * 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.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.springframework.core;
+
+import java.lang.reflect.Method;
+import java.lang.reflect.Proxy;
+import java.util.Arrays;
+import java.util.LinkedHashMap;
+import java.util.LinkedHashSet;
+import java.util.Map;
+import java.util.Set;
+
+import org.springframework.util.ClassUtils;
+import org.springframework.util.ReflectionUtils;
+
+/**
+ * Defines the algorithm for searching for metadata-associated methods exhaustively
+ * including interfaces and parent classes while also dealing with parameterized methods
+ * as well as common scenarios encountered with interface and class-based proxies.
+ *
+ *
Typically, but not necessarily, used for finding annotated handler methods.
+ *
+ * @author Juergen Hoeller
+ * @author Rossen Stoyanchev
+ * @since 4.2.3
+ */
+public abstract class MethodIntrospector {
+
+ /**
+ * Select methods on the given target type based on the lookup of associated metadata.
+ *
Callers define methods of interest through the {@link MetadataLookup} parameter,
+ * allowing to collect the associated metadata into the result map.
+ * @param targetType the target type to search methods on
+ * @param metadataLookup a {@link MetadataLookup} callback to inspect methods of interest,
+ * returning non-null metadata to be associated with a given method if there is a match,
+ * or {@code null} for no match
+ * @return the selected methods associated with their metadata (in the order of retrieval),
+ * or an empty map in case of no match
+ */
+ public static Map selectMethods(Class> targetType, final MetadataLookup metadataLookup) {
+ final Map methodMap = new LinkedHashMap();
+ Set> handlerTypes = new LinkedHashSet>();
+ Class> specificHandlerType = null;
+
+ if (!Proxy.isProxyClass(targetType)) {
+ handlerTypes.add(targetType);
+ specificHandlerType = targetType;
+ }
+ handlerTypes.addAll(Arrays.asList(targetType.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);
+ T result = metadataLookup.inspect(specificMethod);
+ if (result != null) {
+ Method bridgedMethod = BridgeMethodResolver.findBridgedMethod(specificMethod);
+ if (bridgedMethod == specificMethod || metadataLookup.inspect(bridgedMethod) == null) {
+ methodMap.put(specificMethod, result);
+ }
+ }
+ }
+ }, ReflectionUtils.USER_DECLARED_METHODS);
+ }
+
+ return methodMap;
+ }
+
+ /**
+ * Select methods on the given target type based on a filter.
+ *
Callers define methods of interest through the
+ * {@link ReflectionUtils.MethodFilter} parameter.
+ * @param targetType the target type to search methods on
+ * @param methodFilter a {@link ReflectionUtils.MethodFilter} to help
+ * recognize handler methods of interest
+ * @return the selected methods, or an empty set in case of no match
+ */
+ public static Set selectMethods(Class> targetType, final ReflectionUtils.MethodFilter methodFilter) {
+ return selectMethods(targetType, new MetadataLookup() {
+ @Override
+ public Boolean inspect(Method method) {
+ return (methodFilter.matches(method) ? Boolean.TRUE : null);
+ }
+ }).keySet();
+ }
+
+ /**
+ * Select an invocable method on the target type: either the given method itself
+ * if actually exposed on the target type, or otherwise a corresponding method
+ * on one of the target type's interfaces or on the target type itself.
+ *
Matches on user-declared interfaces will be preferred since they are likely
+ * to contain relevant metadata that corresponds to the method on the target class.
+ * @param method the method to check
+ * @param targetType the target type to search methods on
+ * (typically an interface-based JDK proxy)
+ * @return a corresponding invocable method on the target type
+ */
+ public static Method selectInvocableMethod(Method method, Class> targetType) {
+ if (method.getDeclaringClass().isAssignableFrom(targetType)) {
+ return method;
+ }
+ try {
+ for (Class> ifc : targetType.getInterfaces()) {
+ try {
+ return ifc.getMethod(method.getName(), method.getParameterTypes());
+ }
+ catch (NoSuchMethodException ex) {
+ // Alright, not on this interface then...
+ }
+ }
+ // A final desperate attempt on the proxy class itself...
+ return targetType.getMethod(method.getName(), method.getParameterTypes());
+ }
+ catch (NoSuchMethodException ex) {
+ throw new IllegalStateException(String.format(
+ "Need to invoke method '%s' declared on target class '%s', " +
+ "but not found in any interface(s) of the exposed proxy type. " +
+ "Either pull the method up to an interface or switch to CGLIB " +
+ "proxies by enforcing proxy-target-class mode in your configuration.",
+ method.getName(), method.getDeclaringClass().getSimpleName()));
+ }
+ }
+
+
+ /**
+ * A callback interface for metadata lookup on a given method.
+ * @param the type of metadata returned
+ */
+ public interface MetadataLookup {
+
+ /**
+ * Perform a lookup on the given method and return associated metadata, if any.
+ * @param method the method to inspect
+ * @return non-null metadata to be associated with a method if there is a match,
+ * or {@code null} for no match
+ */
+ T inspect(Method method);
+ }
+
+}
diff --git a/spring-messaging/src/main/java/org/springframework/messaging/handler/HandlerMethodSelector.java b/spring-messaging/src/main/java/org/springframework/messaging/handler/HandlerMethodSelector.java
index 86b0a1fa41..69bd0c1aca 100644
--- a/spring-messaging/src/main/java/org/springframework/messaging/handler/HandlerMethodSelector.java
+++ b/spring-messaging/src/main/java/org/springframework/messaging/handler/HandlerMethodSelector.java
@@ -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 selectMethods(final Class> handlerType, final MethodFilter handlerMethodFilter) {
- final Set handlerMethods = new LinkedHashSet();
- Set> handlerTypes = new LinkedHashSet>();
- 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 selectMethods(Class> handlerType, MethodFilter handlerMethodFilter) {
+ return MethodIntrospector.selectMethods(handlerType, handlerMethodFilter);
}
}
diff --git a/spring-messaging/src/main/java/org/springframework/messaging/handler/annotation/support/AnnotationExceptionHandlerMethodResolver.java b/spring-messaging/src/main/java/org/springframework/messaging/handler/annotation/support/AnnotationExceptionHandlerMethodResolver.java
index 03f98a6ab7..cccbc446bc 100644
--- a/spring-messaging/src/main/java/org/springframework/messaging/handler/annotation/support/AnnotationExceptionHandlerMethodResolver.java
+++ b/spring-messaging/src/main/java/org/springframework/messaging/handler/annotation/support/AnnotationExceptionHandlerMethodResolver.java
@@ -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, Method> initExceptionMappings(Class> handlerType) {
+ Map methods = MethodIntrospector.selectMethods(handlerType,
+ new MethodIntrospector.MetadataLookup() {
+ @Override
+ public MessageExceptionHandler inspect(Method method) {
+ return AnnotationUtils.findAnnotation(method, MessageExceptionHandler.class);
+ }
+ });
+
Map, Method> result = new HashMap, Method>();
- for (Method method : HandlerMethodSelector.selectMethods(handlerType, EXCEPTION_HANDLER_METHOD_FILTER)) {
- for (Class extends Throwable> exceptionType : getMappedExceptions(method)) {
+ for (Map.Entry entry : methods.entrySet()) {
+ Method method = entry.getKey();
+ List> exceptionTypes = new ArrayList>();
+ 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> getMappedExceptions(Method method) {
- List> result = new ArrayList>();
- 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
diff --git a/spring-messaging/src/main/java/org/springframework/messaging/handler/invocation/AbstractMethodMessageHandler.java b/spring-messaging/src/main/java/org/springframework/messaging/handler/invocation/AbstractMethodMessageHandler.java
index 69c01809af..639e241560 100644
--- a/spring-messaging/src/main/java/org/springframework/messaging/handler/invocation/AbstractMethodMessageHandler.java
+++ b/spring-messaging/src/main/java/org/springframework/messaging/handler/invocation/AbstractMethodMessageHandler.java
@@ -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 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
* 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 methods = HandlerMethodSelector.selectMethods(userType, new ReflectionUtils.MethodFilter() {
- @Override
- public boolean matches(Method method) {
- return getMappingForMethod(method, userType) != null;
- }
- });
+ Map methods = MethodIntrospector.selectMethods(userType,
+ new MethodIntrospector.MetadataLookup() {
+ @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 entry : methods.entrySet()) {
+ registerHandlerMethod(handler, entry.getKey(), entry.getValue());
}
}
@@ -277,7 +280,6 @@ public abstract class AbstractMethodMessageHandler
*/
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
* 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);
diff --git a/spring-web/src/main/java/org/springframework/web/method/HandlerMethodSelector.java b/spring-web/src/main/java/org/springframework/web/method/HandlerMethodSelector.java
index a659ff2860..82acd2c3bd 100644
--- a/spring-web/src/main/java/org/springframework/web/method/HandlerMethodSelector.java
+++ b/spring-web/src/main/java/org/springframework/web/method/HandlerMethodSelector.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2002-2014 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.
@@ -17,14 +17,9 @@
package org.springframework.web.method;
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 3.1
+ * @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 selectMethods(final Class> handlerType, final MethodFilter handlerMethodFilter) {
- final Set handlerMethods = new LinkedHashSet();
- Set> handlerTypes = new LinkedHashSet>();
- 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 selectMethods(Class> handlerType, MethodFilter handlerMethodFilter) {
+ return MethodIntrospector.selectMethods(handlerType, handlerMethodFilter);
}
}
diff --git a/spring-web/src/main/java/org/springframework/web/method/annotation/ExceptionHandlerMethodResolver.java b/spring-web/src/main/java/org/springframework/web/method/annotation/ExceptionHandlerMethodResolver.java
index 46af047ad8..5d307cba90 100644
--- a/spring-web/src/main/java/org/springframework/web/method/annotation/ExceptionHandlerMethodResolver.java
+++ b/spring-web/src/main/java/org/springframework/web/method/annotation/ExceptionHandlerMethodResolver.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2002-2014 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.
@@ -25,12 +25,12 @@ import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import org.springframework.core.ExceptionDepthComparator;
+import org.springframework.core.MethodIntrospector;
import org.springframework.core.annotation.AnnotationUtils;
import org.springframework.util.Assert;
import org.springframework.util.ClassUtils;
import org.springframework.util.ReflectionUtils.MethodFilter;
import org.springframework.web.bind.annotation.ExceptionHandler;
-import org.springframework.web.method.HandlerMethodSelector;
/**
* Discovers {@linkplain ExceptionHandler @ExceptionHandler} methods in a given class,
@@ -70,7 +70,7 @@ public class ExceptionHandlerMethodResolver {
* @param handlerType the type to introspect
*/
public ExceptionHandlerMethodResolver(Class> handlerType) {
- for (Method method : HandlerMethodSelector.selectMethods(handlerType, EXCEPTION_HANDLER_METHODS)) {
+ for (Method method : MethodIntrospector.selectMethods(handlerType, EXCEPTION_HANDLER_METHODS)) {
for (Class extends Throwable> exceptionType : detectExceptionMappings(method)) {
addExceptionMapping(exceptionType, method);
}
@@ -105,9 +105,8 @@ public class ExceptionHandlerMethodResolver {
private void addExceptionMapping(Class extends Throwable> exceptionType, Method method) {
Method oldMethod = this.mappedMethods.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 + "}");
}
}
diff --git a/spring-web/src/test/java/org/springframework/web/method/annotation/ModelFactoryOrderingTests.java b/spring-web/src/test/java/org/springframework/web/method/annotation/ModelFactoryOrderingTests.java
index 793cc67d50..8d5c7aed34 100644
--- a/spring-web/src/test/java/org/springframework/web/method/annotation/ModelFactoryOrderingTests.java
+++ b/spring-web/src/test/java/org/springframework/web/method/annotation/ModelFactoryOrderingTests.java
@@ -28,6 +28,7 @@ import org.apache.commons.logging.LogFactory;
import org.junit.Before;
import org.junit.Test;
+import org.springframework.core.MethodIntrospector;
import org.springframework.core.annotation.AnnotationUtils;
import org.springframework.mock.web.test.MockHttpServletRequest;
import org.springframework.mock.web.test.MockHttpServletResponse;
@@ -42,7 +43,6 @@ import org.springframework.web.bind.support.WebDataBinderFactory;
import org.springframework.web.context.request.NativeWebRequest;
import org.springframework.web.context.request.ServletWebRequest;
import org.springframework.web.method.HandlerMethod;
-import org.springframework.web.method.HandlerMethodSelector;
import org.springframework.web.method.support.HandlerMethodArgumentResolverComposite;
import org.springframework.web.method.support.InvocableHandlerMethod;
import org.springframework.web.method.support.ModelAndViewContainer;
@@ -119,7 +119,7 @@ public class ModelFactoryOrderingTests {
WebDataBinderFactory dataBinderFactory = new DefaultDataBinderFactory(null);
Class> type = controller.getClass();
- Set methods = HandlerMethodSelector.selectMethods(type, METHOD_FILTER);
+ Set methods = MethodIntrospector.selectMethods(type, METHOD_FILTER);
List modelMethods = new ArrayList();
for (Method method : methods) {
InvocableHandlerMethod modelMethod = new InvocableHandlerMethod(controller, method);
diff --git a/spring-webmvc/src/main/java/org/springframework/web/servlet/handler/AbstractHandlerMethodMapping.java b/spring-webmvc/src/main/java/org/springframework/web/servlet/handler/AbstractHandlerMethodMapping.java
index bf4eb7d131..7e1c50f12d 100644
--- a/spring-webmvc/src/main/java/org/springframework/web/servlet/handler/AbstractHandlerMethodMapping.java
+++ b/spring-webmvc/src/main/java/org/springframework/web/servlet/handler/AbstractHandlerMethodMapping.java
@@ -22,7 +22,6 @@ import java.util.Collection;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
-import java.util.IdentityHashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
@@ -34,15 +33,14 @@ import javax.servlet.http.HttpServletRequest;
import org.springframework.beans.factory.BeanFactoryUtils;
import org.springframework.beans.factory.InitializingBean;
+import org.springframework.core.MethodIntrospector;
import org.springframework.util.Assert;
import org.springframework.util.ClassUtils;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
-import org.springframework.util.ReflectionUtils.MethodFilter;
import org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.cors.CorsUtils;
import org.springframework.web.method.HandlerMethod;
-import org.springframework.web.method.HandlerMethodSelector;
import org.springframework.web.servlet.HandlerMapping;
/**
@@ -197,29 +195,23 @@ public abstract class AbstractHandlerMethodMapping extends AbstractHandlerMap
* @param handler the bean name of a handler or a handler instance
*/
protected void detectHandlerMethods(final Object handler) {
- Class> handlerType =
- (handler instanceof String ? getApplicationContext().getType((String) handler) : handler.getClass());
-
- // Avoid repeated calls to getMappingForMethod which would rebuild RequestMappingInfo instances
- final Map mappings = new IdentityHashMap();
+ Class> handlerType = (handler instanceof String ?
+ getApplicationContext().getType((String) handler) : handler.getClass());
final Class> userType = ClassUtils.getUserClass(handlerType);
- Set methods = HandlerMethodSelector.selectMethods(userType, new MethodFilter() {
- @Override
- public boolean matches(Method method) {
- T mapping = getMappingForMethod(method, userType);
- if (mapping != null) {
- mappings.put(method, mapping);
- return true;
- }
- else {
- return false;
- }
- }
- });
+ Map methods = MethodIntrospector.selectMethods(userType,
+ new MethodIntrospector.MetadataLookup() {
+ @Override
+ public T inspect(Method method) {
+ return getMappingForMethod(method, userType);
+ }
+ });
- for (Method method : methods) {
- registerHandlerMethod(handler, method, mappings.get(method));
+ if (logger.isDebugEnabled()) {
+ logger.debug(methods.size() + " request handler methods found on " + userType + ": " + methods);
+ }
+ for (Map.Entry entry : methods.entrySet()) {
+ registerHandlerMethod(handler, entry.getKey(), entry.getValue());
}
}
@@ -241,12 +233,7 @@ public abstract class AbstractHandlerMethodMapping extends AbstractHandlerMap
* @param mapping the mapping conditions associated with the handler method
* @throws IllegalStateException if another method was already registered
* under the same mapping
- * @deprecated as of 4.2. You can now invoke the public methods
- * {@link #registerMapping(Object, Object, Method)} and
- * {@link #unregisterMapping(Object)} during initialization or at runtime,
- * i.e. after initialization is complete.
*/
- @Deprecated
protected void registerHandlerMethod(Object handler, Method method, T mapping) {
this.mappingRegistry.register(mapping, handler, method);
}
@@ -443,7 +430,7 @@ public abstract class AbstractHandlerMethodMapping extends AbstractHandlerMap
}
else {
CorsConfiguration corsConfigFromMethod = this.mappingRegistry.getCorsConfiguration(handlerMethod);
- corsConfig = (corsConfig == null ? corsConfigFromMethod : corsConfig.combine(corsConfigFromMethod));
+ corsConfig = (corsConfig != null ? corsConfig.combine(corsConfigFromMethod) : corsConfigFromMethod);
}
}
return corsConfig;
@@ -470,10 +457,8 @@ public abstract class AbstractHandlerMethodMapping extends AbstractHandlerMap
private final Map corsLookup =
new ConcurrentHashMap();
-
private final ReentrantReadWriteLock readWriteLock = new ReentrantReadWriteLock();
-
/**
* Return all mappings and handler methods. Not thread-safe.
* @see #acquireReadLock()
@@ -521,7 +506,6 @@ public abstract class AbstractHandlerMethodMapping extends AbstractHandlerMap
public void register(T mapping, Object handler, Method method) {
-
this.readWriteLock.writeLock().lock();
try {
HandlerMethod handlerMethod = createHandlerMethod(handler, method);
@@ -560,8 +544,8 @@ public abstract class AbstractHandlerMethodMapping extends AbstractHandlerMap
if (handlerMethod != null && !handlerMethod.equals(newHandlerMethod)) {
throw new IllegalStateException(
"Ambiguous mapping. Cannot map '" + newHandlerMethod.getBean() + "' method \n" +
- newHandlerMethod + "\nto " + mapping + ": There is already '" +
- handlerMethod.getBean() + "' bean method\n" + handlerMethod + " mapped.");
+ newHandlerMethod + "\nto " + mapping + ": There is already '" +
+ handlerMethod.getBean() + "' bean method\n" + handlerMethod + " mapped.");
}
}
@@ -576,9 +560,10 @@ public abstract class AbstractHandlerMethodMapping extends AbstractHandlerMap
}
private void addMappingName(String name, HandlerMethod handlerMethod) {
-
- List oldList = this.nameLookup.containsKey(name) ?
- this.nameLookup.get(name) : Collections.emptyList();
+ List oldList = this.nameLookup.get(name);
+ if (oldList == null) {
+ oldList = Collections.emptyList();
+ }
for (HandlerMethod current : oldList) {
if (handlerMethod.equals(current)) {
@@ -587,7 +572,7 @@ public abstract class AbstractHandlerMethodMapping extends AbstractHandlerMap
}
if (logger.isTraceEnabled()) {
- logger.trace("Mapping name=" + name);
+ logger.trace("Mapping name '" + name + "'");
}
List newList = new ArrayList(oldList.size() + 1);
@@ -597,7 +582,7 @@ public abstract class AbstractHandlerMethodMapping extends AbstractHandlerMap
if (newList.size() > 1) {
if (logger.isTraceEnabled()) {
- logger.trace("Mapping name clash for handlerMethods=" + newList +
+ logger.trace("Mapping name clash for handlerMethods " + newList +
". Consider assigning explicit names.");
}
}
@@ -654,9 +639,9 @@ public abstract class AbstractHandlerMethodMapping extends AbstractHandlerMap
}
this.nameLookup.put(name, newList);
}
-
}
+
private static class MappingRegistration {
private final T mapping;
@@ -667,20 +652,15 @@ public abstract class AbstractHandlerMethodMapping extends AbstractHandlerMap
private final String mappingName;
-
- public MappingRegistration(T mapping, HandlerMethod handlerMethod,
- List directUrls, String mappingName) {
-
+ public MappingRegistration(T mapping, HandlerMethod handlerMethod, List directUrls, String mappingName) {
Assert.notNull(mapping);
Assert.notNull(handlerMethod);
-
this.mapping = mapping;
this.handlerMethod = handlerMethod;
this.directUrls = (directUrls != null ? directUrls : Collections.emptyList());
this.mappingName = mappingName;
}
-
public T getMapping() {
return this.mapping;
}
diff --git a/spring-webmvc/src/main/java/org/springframework/web/servlet/mvc/method/annotation/MvcUriComponentsBuilder.java b/spring-webmvc/src/main/java/org/springframework/web/servlet/mvc/method/annotation/MvcUriComponentsBuilder.java
index bc2cb41831..e8ff7ee93a 100644
--- a/spring-webmvc/src/main/java/org/springframework/web/servlet/mvc/method/annotation/MvcUriComponentsBuilder.java
+++ b/spring-webmvc/src/main/java/org/springframework/web/servlet/mvc/method/annotation/MvcUriComponentsBuilder.java
@@ -39,6 +39,7 @@ import org.springframework.cglib.proxy.Factory;
import org.springframework.cglib.proxy.MethodProxy;
import org.springframework.core.DefaultParameterNameDiscoverer;
import org.springframework.core.MethodParameter;
+import org.springframework.core.MethodIntrospector;
import org.springframework.core.ParameterNameDiscoverer;
import org.springframework.core.annotation.AnnotatedElementUtils;
import org.springframework.core.annotation.SynthesizingMethodParameter;
@@ -57,7 +58,6 @@ import org.springframework.web.context.request.RequestAttributes;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import org.springframework.web.method.HandlerMethod;
-import org.springframework.web.method.HandlerMethodSelector;
import org.springframework.web.method.annotation.RequestParamMethodArgumentResolver;
import org.springframework.web.method.support.CompositeUriComponentsContributor;
import org.springframework.web.servlet.DispatcherServlet;
@@ -454,7 +454,7 @@ public class MvcUriComponentsBuilder {
return (name.equals(methodName) && argLength == args.length);
}
};
- Set methods = HandlerMethodSelector.selectMethods(controllerType, selector);
+ Set methods = MethodIntrospector.selectMethods(controllerType, selector);
if (methods.size() == 1) {
return methods.iterator().next();
}
diff --git a/spring-webmvc/src/main/java/org/springframework/web/servlet/mvc/method/annotation/RequestMappingHandlerAdapter.java b/spring-webmvc/src/main/java/org/springframework/web/servlet/mvc/method/annotation/RequestMappingHandlerAdapter.java
index b0e087414b..a1c8e09443 100644
--- a/spring-webmvc/src/main/java/org/springframework/web/servlet/mvc/method/annotation/RequestMappingHandlerAdapter.java
+++ b/spring-webmvc/src/main/java/org/springframework/web/servlet/mvc/method/annotation/RequestMappingHandlerAdapter.java
@@ -35,6 +35,7 @@ import org.springframework.beans.factory.BeanFactoryAware;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.config.ConfigurableBeanFactory;
import org.springframework.core.DefaultParameterNameDiscoverer;
+import org.springframework.core.MethodIntrospector;
import org.springframework.core.ParameterNameDiscoverer;
import org.springframework.core.annotation.AnnotationAwareOrderComparator;
import org.springframework.core.annotation.AnnotationUtils;
@@ -70,7 +71,6 @@ import org.springframework.web.context.request.async.WebAsyncTask;
import org.springframework.web.context.request.async.WebAsyncUtils;
import org.springframework.web.method.ControllerAdviceBean;
import org.springframework.web.method.HandlerMethod;
-import org.springframework.web.method.HandlerMethodSelector;
import org.springframework.web.method.annotation.ErrorsMethodArgumentResolver;
import org.springframework.web.method.annotation.ExpressionValueMethodArgumentResolver;
import org.springframework.web.method.annotation.InitBinderDataBinderFactory;
@@ -538,23 +538,31 @@ public class RequestMappingHandlerAdapter extends AbstractHandlerMethodAdapter
List