diff --git a/spring-context/src/main/java/org/springframework/context/event/EventListenerMethodProcessor.java b/spring-context/src/main/java/org/springframework/context/event/EventListenerMethodProcessor.java index 15779599cd..d551d509e5 100644 --- a/spring-context/src/main/java/org/springframework/context/event/EventListenerMethodProcessor.java +++ b/spring-context/src/main/java/org/springframework/context/event/EventListenerMethodProcessor.java @@ -72,8 +72,8 @@ public class EventListenerMethodProcessor implements SmartInitializingSingleton, @Override public void afterSingletonsInstantiated() { List factories = getEventListenerFactories(); - String[] allBeanNames = this.applicationContext.getBeanNamesForType(Object.class); - for (String beanName : allBeanNames) { + String[] beanNames = this.applicationContext.getBeanNamesForType(Object.class); + for (String beanName : beanNames) { if (!ScopedProxyUtils.isScopedTarget(beanName)) { Class type = null; try { diff --git a/spring-core/src/main/java/org/springframework/core/annotation/AnnotationUtils.java b/spring-core/src/main/java/org/springframework/core/annotation/AnnotationUtils.java index c504db73a2..f7eb74cd01 100644 --- a/spring-core/src/main/java/org/springframework/core/annotation/AnnotationUtils.java +++ b/spring-core/src/main/java/org/springframework/core/annotation/AnnotationUtils.java @@ -456,8 +456,8 @@ public abstract class AnnotationUtils { private static Set getRepeatableAnnotations(AnnotatedElement annotatedElement, Class annotationType, Class containerAnnotationType, boolean declaredMode) { - Assert.notNull(annotatedElement, "annotatedElement must not be null"); - Assert.notNull(annotationType, "annotationType must not be null"); + Assert.notNull(annotatedElement, "AnnotatedElement must not be null"); + Assert.notNull(annotationType, "Annotation type must not be null"); try { if (annotatedElement instanceof Method) { @@ -488,6 +488,11 @@ public abstract class AnnotationUtils { * @since 4.2 */ public static A findAnnotation(AnnotatedElement annotatedElement, Class annotationType) { + Assert.notNull(annotatedElement, "AnnotatedElement must not be null"); + if (annotationType == null) { + return null; + } + // Do NOT store result in the findAnnotationCache since doing so could break // findAnnotation(Class, Class) and findAnnotation(Method, Class). return synthesizeAnnotation( @@ -506,7 +511,6 @@ public abstract class AnnotationUtils { */ @SuppressWarnings("unchecked") private static A findAnnotation(AnnotatedElement annotatedElement, Class annotationType, Set visited) { - Assert.notNull(annotatedElement, "AnnotatedElement must not be null"); try { Annotation[] anns = annotatedElement.getDeclaredAnnotations(); for (Annotation ann : anns) { @@ -546,6 +550,11 @@ public abstract class AnnotationUtils { */ @SuppressWarnings("unchecked") public static A findAnnotation(Method method, Class annotationType) { + Assert.notNull(method, "Method must not be null"); + if (annotationType == null) { + return null; + } + AnnotationCacheKey cacheKey = new AnnotationCacheKey(method, annotationType); A result = (A) findAnnotationCache.get(cacheKey); @@ -663,6 +672,11 @@ public abstract class AnnotationUtils { */ @SuppressWarnings("unchecked") private static A findAnnotation(Class clazz, Class annotationType, boolean synthesize) { + Assert.notNull(clazz, "Class must not be null"); + if (annotationType == null) { + return null; + } + AnnotationCacheKey cacheKey = new AnnotationCacheKey(clazz, annotationType); A result = (A) findAnnotationCache.get(cacheKey); if (result == null) { @@ -686,8 +700,6 @@ public abstract class AnnotationUtils { */ @SuppressWarnings("unchecked") private static A findAnnotation(Class clazz, Class annotationType, Set visited) { - Assert.notNull(clazz, "Class must not be null"); - try { Annotation[] anns = clazz.getDeclaredAnnotations(); for (Annotation ann : anns) { @@ -863,6 +875,11 @@ public abstract class AnnotationUtils { public static boolean isAnnotationMetaPresent(Class annotationType, Class metaAnnotationType) { + Assert.notNull(annotationType, "Annotation type must not be null"); + if (metaAnnotationType == null) { + return false; + } + AnnotationCacheKey cacheKey = new AnnotationCacheKey(annotationType, metaAnnotationType); Boolean metaPresent = metaPresentCache.get(cacheKey); if (metaPresent != null) { @@ -1760,8 +1777,7 @@ public abstract class AnnotationUtils { return false; } AnnotationCacheKey otherKey = (AnnotationCacheKey) other; - return (this.element.equals(otherKey.element) && - ObjectUtils.nullSafeEquals(this.annotationType, otherKey.annotationType)); + return (this.element.equals(otherKey.element) && this.annotationType.equals(otherKey.annotationType)); } @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 639e241560..c007c9d22a 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 @@ -33,8 +33,8 @@ import org.apache.commons.logging.LogFactory; 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.core.MethodParameter; import org.springframework.messaging.Message; import org.springframework.messaging.MessageHandler; import org.springframework.messaging.MessagingException; @@ -68,6 +68,19 @@ import org.springframework.util.concurrent.ListenableFutureCallback; public abstract class AbstractMethodMessageHandler implements MessageHandler, ApplicationContextAware, InitializingBean { + /** + * Bean name prefix for target beans behind scoped proxies. Used to exclude those + * targets from handler method detection, in favor of the corresponding proxies. + *

We're not checking the autowire-candidate status here, which is how the + * proxy target filtering problem is being handled at the autowiring level, + * since autowire-candidate may have been turned to {@code false} for other + * reasons, while still expecting the bean to be eligible for handler methods. + *

Originally defined in {@link org.springframework.aop.scope.ScopedProxyUtils} + * but duplicated here to avoid a hard dependency on the spring-aop module. + */ + private static final String SCOPED_TARGET_NAME_PREFIX = "scopedTarget."; + + protected final Log logger = LogFactory.getLog(getClass()); private Collection destinationPrefixes = new ArrayList(); @@ -218,8 +231,20 @@ public abstract class AbstractMethodMessageHandler } for (String beanName : this.applicationContext.getBeanNamesForType(Object.class)) { - if (isHandler(this.applicationContext.getType(beanName))){ - detectHandlerMethods(beanName); + if (!beanName.startsWith(SCOPED_TARGET_NAME_PREFIX)) { + Class beanType = null; + try { + beanType = getApplicationContext().getType(beanName); + } + catch (Throwable ex) { + // An unresolvable bean type, probably from a lazy bean - let's ignore it. + if (logger.isDebugEnabled()) { + logger.debug("Could not resolve target class for bean with name '" + beanName + "'", ex); + } + } + if (beanType != null && isHandler(beanType)) { + detectHandlerMethods(beanName); + } } } } 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 7e1c50f12d..99386e074a 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 @@ -175,9 +175,21 @@ public abstract class AbstractHandlerMethodMapping extends AbstractHandlerMap BeanFactoryUtils.beanNamesForTypeIncludingAncestors(getApplicationContext(), Object.class) : getApplicationContext().getBeanNamesForType(Object.class)); - for (String name : beanNames) { - if (!name.startsWith(SCOPED_TARGET_NAME_PREFIX) && isHandler(getApplicationContext().getType(name))) { - detectHandlerMethods(name); + for (String beanName : beanNames) { + if (!beanName.startsWith(SCOPED_TARGET_NAME_PREFIX)) { + Class beanType = null; + try { + beanType = getApplicationContext().getType(beanName); + } + catch (Throwable ex) { + // An unresolvable bean type, probably from a lazy bean - let's ignore it. + if (logger.isDebugEnabled()) { + logger.debug("Could not resolve target class for bean with name '" + beanName + "'", ex); + } + } + if (beanType != null && isHandler(beanType)) { + detectHandlerMethods(beanName); + } } } handlerMethodsInitialized(getHandlerMethods());