Skip to content

Commit b121c50

Browse files
Christopher RuedChristopher Rued
authored andcommitted
Enhance AnnotationUtils to find annotations on generic interfaces
When scanning for annotations on a class that implements a generic interface where the generic type is specified in the implementing class, annotation scanning would fail to identify annotations from the interface since the parameter types do not match. For example, given an interface: public interface Foo<T> { @order void foo(T t); } and a class public class StringFoo implements Foo<String> { public void foo(String s) { ... } } when scanning StringFoo.foo for annotations, no annotations were identified. This commit changes annotation scanning so that when scanning for annotations, the parameters are compared for assignability (using Class.isAssignableFrom()) rather than requiring exact matches. Issue: SEC-3081 Correct formatting
1 parent 3febec3 commit b121c50

File tree

3 files changed

+53
-8
lines changed

3 files changed

+53
-8
lines changed

.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,3 +38,5 @@ out
3838
test-output
3939
atlassian-ide-plugin.xml
4040
.gradletasknamecache
41+
/.nb-gradle/
42+

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

Lines changed: 33 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -581,21 +581,46 @@ private static <A extends Annotation> A searchOnInterfaces(Method method, Class<
581581
A annotation = null;
582582
for (Class<?> iface : ifcs) {
583583
if (isInterfaceWithAnnotatedMethods(iface)) {
584-
try {
585-
Method equivalentMethod = iface.getMethod(method.getName(), method.getParameterTypes());
584+
Method equivalentMethod = findMethodWithMatchingParameters(iface, method.getName(), method.getParameterTypes());
585+
if (equivalentMethod != null) {
586586
annotation = getAnnotation(equivalentMethod, annotationType);
587-
}
588-
catch (NoSuchMethodException ex) {
589-
// Skip this interface - it doesn't have the method...
590-
}
591-
if (annotation != null) {
592-
break;
587+
if (annotation != null) {
588+
break;
589+
}
593590
}
594591
}
595592
}
596593
return annotation;
597594
}
598595

596+
private static Method findMethodWithMatchingParameters(Class<?> cls, String methodName, Class<?>[] parameterTypes) {
597+
try {
598+
// first try exact match
599+
return cls.getMethod(methodName, parameterTypes);
600+
} catch (NoSuchMethodException e) {
601+
// then look for method with assignable parameters
602+
for (Method method : cls.getMethods()) {
603+
if (method.getName().equals(methodName) &&
604+
method.getParameterCount() == parameterTypes.length &&
605+
parametersAreAssignable(parameterTypes, method)) {
606+
return method;
607+
}
608+
}
609+
}
610+
// return null if there is no match
611+
return null;
612+
}
613+
614+
@SuppressWarnings("unchecked")
615+
private static boolean parametersAreAssignable(Class<?>[] parameterTypes, Method method) {
616+
for (int j = 0; j < parameterTypes.length; j++) {
617+
if (!method.getParameterTypes()[j].isAssignableFrom(parameterTypes[j])) {
618+
return false;
619+
}
620+
}
621+
return true;
622+
}
623+
599624
static boolean isInterfaceWithAnnotatedMethods(Class<?> iface) {
600625
Boolean found = annotatedInterfaceCache.get(iface);
601626
if (found != null) {

spring-core/src/test/java/org/springframework/core/annotation/AnnotationUtilsTests.java

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -194,6 +194,13 @@ public void findMethodAnnotationFromInterface() throws Exception {
194194
assertNotNull(order);
195195
}
196196

197+
@Test
198+
public void findMethodAnnotationFromGenericInterfaceSuper() throws Exception {
199+
Method method = ImplementsInterfaceWithGenericAnnotatedMethod.class.getMethod("foo", String.class);
200+
Order order = findAnnotation(method, Order.class);
201+
assertNotNull(order);
202+
}
203+
197204
@Test
198205
public void findMethodAnnotationFromInterfaceOnSuper() throws Exception {
199206
Method method = SubOfImplementsInterfaceWithAnnotatedMethod.class.getMethod("foo");
@@ -1755,6 +1762,17 @@ public static class TransactionalAndOrderedClass extends TransactionalClass {
17551762
public static class SubTransactionalAndOrderedClass extends TransactionalAndOrderedClass {
17561763
}
17571764

1765+
public static interface InterfaceWithGenericAnnotatedMethod<T> {
1766+
@Order
1767+
void foo(T t);
1768+
}
1769+
1770+
public static class ImplementsInterfaceWithGenericAnnotatedMethod implements InterfaceWithGenericAnnotatedMethod<String> {
1771+
public void foo(String t) {
1772+
// no body in test method
1773+
}
1774+
}
1775+
17581776
public interface InterfaceWithAnnotatedMethod {
17591777

17601778
@Order

0 commit comments

Comments
 (0)