Skip to content

Commit a0747c2

Browse files
committed
Consistent bean type checking for endpoint handlers
Issue: SPR-13725
1 parent c90ca15 commit a0747c2

File tree

4 files changed

+68
-15
lines changed

4 files changed

+68
-15
lines changed

spring-context/src/main/java/org/springframework/context/event/EventListenerMethodProcessor.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -72,8 +72,8 @@ public void setApplicationContext(ApplicationContext applicationContext) throws
7272
@Override
7373
public void afterSingletonsInstantiated() {
7474
List<EventListenerFactory> factories = getEventListenerFactories();
75-
String[] allBeanNames = this.applicationContext.getBeanNamesForType(Object.class);
76-
for (String beanName : allBeanNames) {
75+
String[] beanNames = this.applicationContext.getBeanNamesForType(Object.class);
76+
for (String beanName : beanNames) {
7777
if (!ScopedProxyUtils.isScopedTarget(beanName)) {
7878
Class<?> type = null;
7979
try {

spring-core/src/main/java/org/springframework/core/annotation/AnnotationUtils.java

Lines changed: 23 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -456,8 +456,8 @@ public static <A extends Annotation> Set<A> getDeclaredRepeatableAnnotations(Ann
456456
private static <A extends Annotation> Set<A> getRepeatableAnnotations(AnnotatedElement annotatedElement,
457457
Class<A> annotationType, Class<? extends Annotation> containerAnnotationType, boolean declaredMode) {
458458

459-
Assert.notNull(annotatedElement, "annotatedElement must not be null");
460-
Assert.notNull(annotationType, "annotationType must not be null");
459+
Assert.notNull(annotatedElement, "AnnotatedElement must not be null");
460+
Assert.notNull(annotationType, "Annotation type must not be null");
461461

462462
try {
463463
if (annotatedElement instanceof Method) {
@@ -488,6 +488,11 @@ private static <A extends Annotation> Set<A> getRepeatableAnnotations(AnnotatedE
488488
* @since 4.2
489489
*/
490490
public static <A extends Annotation> A findAnnotation(AnnotatedElement annotatedElement, Class<A> annotationType) {
491+
Assert.notNull(annotatedElement, "AnnotatedElement must not be null");
492+
if (annotationType == null) {
493+
return null;
494+
}
495+
491496
// Do NOT store result in the findAnnotationCache since doing so could break
492497
// findAnnotation(Class, Class) and findAnnotation(Method, Class).
493498
return synthesizeAnnotation(
@@ -506,7 +511,6 @@ public static <A extends Annotation> A findAnnotation(AnnotatedElement annotated
506511
*/
507512
@SuppressWarnings("unchecked")
508513
private static <A extends Annotation> A findAnnotation(AnnotatedElement annotatedElement, Class<A> annotationType, Set<Annotation> visited) {
509-
Assert.notNull(annotatedElement, "AnnotatedElement must not be null");
510514
try {
511515
Annotation[] anns = annotatedElement.getDeclaredAnnotations();
512516
for (Annotation ann : anns) {
@@ -546,6 +550,11 @@ private static <A extends Annotation> A findAnnotation(AnnotatedElement annotate
546550
*/
547551
@SuppressWarnings("unchecked")
548552
public static <A extends Annotation> A findAnnotation(Method method, Class<A> annotationType) {
553+
Assert.notNull(method, "Method must not be null");
554+
if (annotationType == null) {
555+
return null;
556+
}
557+
549558
AnnotationCacheKey cacheKey = new AnnotationCacheKey(method, annotationType);
550559
A result = (A) findAnnotationCache.get(cacheKey);
551560

@@ -663,6 +672,11 @@ public static <A extends Annotation> A findAnnotation(Class<?> clazz, Class<A> a
663672
*/
664673
@SuppressWarnings("unchecked")
665674
private static <A extends Annotation> A findAnnotation(Class<?> clazz, Class<A> annotationType, boolean synthesize) {
675+
Assert.notNull(clazz, "Class must not be null");
676+
if (annotationType == null) {
677+
return null;
678+
}
679+
666680
AnnotationCacheKey cacheKey = new AnnotationCacheKey(clazz, annotationType);
667681
A result = (A) findAnnotationCache.get(cacheKey);
668682
if (result == null) {
@@ -686,8 +700,6 @@ private static <A extends Annotation> A findAnnotation(Class<?> clazz, Class<A>
686700
*/
687701
@SuppressWarnings("unchecked")
688702
private static <A extends Annotation> A findAnnotation(Class<?> clazz, Class<A> annotationType, Set<Annotation> visited) {
689-
Assert.notNull(clazz, "Class must not be null");
690-
691703
try {
692704
Annotation[] anns = clazz.getDeclaredAnnotations();
693705
for (Annotation ann : anns) {
@@ -863,6 +875,11 @@ public static boolean isAnnotationInherited(Class<? extends Annotation> annotati
863875
public static boolean isAnnotationMetaPresent(Class<? extends Annotation> annotationType,
864876
Class<? extends Annotation> metaAnnotationType) {
865877

878+
Assert.notNull(annotationType, "Annotation type must not be null");
879+
if (metaAnnotationType == null) {
880+
return false;
881+
}
882+
866883
AnnotationCacheKey cacheKey = new AnnotationCacheKey(annotationType, metaAnnotationType);
867884
Boolean metaPresent = metaPresentCache.get(cacheKey);
868885
if (metaPresent != null) {
@@ -1760,8 +1777,7 @@ public boolean equals(Object other) {
17601777
return false;
17611778
}
17621779
AnnotationCacheKey otherKey = (AnnotationCacheKey) other;
1763-
return (this.element.equals(otherKey.element) &&
1764-
ObjectUtils.nullSafeEquals(this.annotationType, otherKey.annotationType));
1780+
return (this.element.equals(otherKey.element) && this.annotationType.equals(otherKey.annotationType));
17651781
}
17661782

17671783
@Override

spring-messaging/src/main/java/org/springframework/messaging/handler/invocation/AbstractMethodMessageHandler.java

Lines changed: 28 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -33,8 +33,8 @@
3333
import org.springframework.beans.factory.InitializingBean;
3434
import org.springframework.context.ApplicationContext;
3535
import org.springframework.context.ApplicationContextAware;
36-
import org.springframework.core.MethodParameter;
3736
import org.springframework.core.MethodIntrospector;
37+
import org.springframework.core.MethodParameter;
3838
import org.springframework.messaging.Message;
3939
import org.springframework.messaging.MessageHandler;
4040
import org.springframework.messaging.MessagingException;
@@ -68,6 +68,19 @@
6868
public abstract class AbstractMethodMessageHandler<T>
6969
implements MessageHandler, ApplicationContextAware, InitializingBean {
7070

71+
/**
72+
* Bean name prefix for target beans behind scoped proxies. Used to exclude those
73+
* targets from handler method detection, in favor of the corresponding proxies.
74+
* <p>We're not checking the autowire-candidate status here, which is how the
75+
* proxy target filtering problem is being handled at the autowiring level,
76+
* since autowire-candidate may have been turned to {@code false} for other
77+
* reasons, while still expecting the bean to be eligible for handler methods.
78+
* <p>Originally defined in {@link org.springframework.aop.scope.ScopedProxyUtils}
79+
* but duplicated here to avoid a hard dependency on the spring-aop module.
80+
*/
81+
private static final String SCOPED_TARGET_NAME_PREFIX = "scopedTarget.";
82+
83+
7184
protected final Log logger = LogFactory.getLog(getClass());
7285

7386
private Collection<String> destinationPrefixes = new ArrayList<String>();
@@ -218,8 +231,20 @@ public void afterPropertiesSet() {
218231
}
219232

220233
for (String beanName : this.applicationContext.getBeanNamesForType(Object.class)) {
221-
if (isHandler(this.applicationContext.getType(beanName))){
222-
detectHandlerMethods(beanName);
234+
if (!beanName.startsWith(SCOPED_TARGET_NAME_PREFIX)) {
235+
Class<?> beanType = null;
236+
try {
237+
beanType = getApplicationContext().getType(beanName);
238+
}
239+
catch (Throwable ex) {
240+
// An unresolvable bean type, probably from a lazy bean - let's ignore it.
241+
if (logger.isDebugEnabled()) {
242+
logger.debug("Could not resolve target class for bean with name '" + beanName + "'", ex);
243+
}
244+
}
245+
if (beanType != null && isHandler(beanType)) {
246+
detectHandlerMethods(beanName);
247+
}
223248
}
224249
}
225250
}

spring-webmvc/src/main/java/org/springframework/web/servlet/handler/AbstractHandlerMethodMapping.java

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -175,9 +175,21 @@ protected void initHandlerMethods() {
175175
BeanFactoryUtils.beanNamesForTypeIncludingAncestors(getApplicationContext(), Object.class) :
176176
getApplicationContext().getBeanNamesForType(Object.class));
177177

178-
for (String name : beanNames) {
179-
if (!name.startsWith(SCOPED_TARGET_NAME_PREFIX) && isHandler(getApplicationContext().getType(name))) {
180-
detectHandlerMethods(name);
178+
for (String beanName : beanNames) {
179+
if (!beanName.startsWith(SCOPED_TARGET_NAME_PREFIX)) {
180+
Class<?> beanType = null;
181+
try {
182+
beanType = getApplicationContext().getType(beanName);
183+
}
184+
catch (Throwable ex) {
185+
// An unresolvable bean type, probably from a lazy bean - let's ignore it.
186+
if (logger.isDebugEnabled()) {
187+
logger.debug("Could not resolve target class for bean with name '" + beanName + "'", ex);
188+
}
189+
}
190+
if (beanType != null && isHandler(beanType)) {
191+
detectHandlerMethods(beanName);
192+
}
181193
}
182194
}
183195
handlerMethodsInitialized(getHandlerMethods());

0 commit comments

Comments
 (0)