Find annotations on implemented generic interface methods as well
Issue: SPR-16060
This commit is contained in:
@@ -39,6 +39,7 @@ import org.apache.commons.logging.Log;
|
|||||||
import org.apache.commons.logging.LogFactory;
|
import org.apache.commons.logging.LogFactory;
|
||||||
|
|
||||||
import org.springframework.core.BridgeMethodResolver;
|
import org.springframework.core.BridgeMethodResolver;
|
||||||
|
import org.springframework.core.ResolvableType;
|
||||||
import org.springframework.lang.Nullable;
|
import org.springframework.lang.Nullable;
|
||||||
import org.springframework.util.Assert;
|
import org.springframework.util.Assert;
|
||||||
import org.springframework.util.ClassUtils;
|
import org.springframework.util.ClassUtils;
|
||||||
@@ -588,8 +589,7 @@ public abstract class AnnotationUtils {
|
|||||||
Set<Method> annotatedMethods = getAnnotatedMethodsInBaseType(ifc);
|
Set<Method> annotatedMethods = getAnnotatedMethodsInBaseType(ifc);
|
||||||
if (!annotatedMethods.isEmpty()) {
|
if (!annotatedMethods.isEmpty()) {
|
||||||
for (Method annotatedMethod : annotatedMethods) {
|
for (Method annotatedMethod : annotatedMethods) {
|
||||||
if (annotatedMethod.getName().equals(method.getName()) &&
|
if (isOverride(method, annotatedMethod)) {
|
||||||
Arrays.equals(annotatedMethod.getParameterTypes(), method.getParameterTypes())) {
|
|
||||||
A annotation = getAnnotation(annotatedMethod, annotationType);
|
A annotation = getAnnotation(annotatedMethod, annotationType);
|
||||||
if (annotation != null) {
|
if (annotation != null) {
|
||||||
return annotation;
|
return annotation;
|
||||||
@@ -647,6 +647,23 @@ public abstract class AnnotationUtils {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static boolean isOverride(Method method, Method candidate) {
|
||||||
|
if (!candidate.getName().equals(method.getName()) ||
|
||||||
|
candidate.getParameterCount() != method.getParameterCount()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
Class<?>[] paramTypes = method.getParameterTypes();
|
||||||
|
if (Arrays.equals(candidate.getParameterTypes(), paramTypes)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
for (int i = 0; i < paramTypes.length; i++) {
|
||||||
|
if (paramTypes[i] != ResolvableType.forMethodParameter(candidate, i, method.getDeclaringClass()).resolve()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Find a single {@link Annotation} of {@code annotationType} on the
|
* Find a single {@link Annotation} of {@code annotationType} on the
|
||||||
* supplied {@link Class}, traversing its interfaces, annotations, and
|
* supplied {@link Class}, traversing its interfaces, annotations, and
|
||||||
|
|||||||
@@ -178,6 +178,13 @@ public class AnnotationUtilsTests {
|
|||||||
assertNotNull(order);
|
assertNotNull(order);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test // SPR-16060
|
||||||
|
public void findMethodAnnotationFromGenericInterface() throws Exception {
|
||||||
|
Method method = ImplementsInterfaceWithGenericAnnotatedMethod.class.getMethod("foo", String.class);
|
||||||
|
Order order = findAnnotation(method, Order.class);
|
||||||
|
assertNotNull(order);
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void findMethodAnnotationFromInterfaceOnSuper() throws Exception {
|
public void findMethodAnnotationFromInterfaceOnSuper() throws Exception {
|
||||||
Method method = SubOfImplementsInterfaceWithAnnotatedMethod.class.getMethod("foo");
|
Method method = SubOfImplementsInterfaceWithAnnotatedMethod.class.getMethod("foo");
|
||||||
@@ -286,7 +293,7 @@ public class AnnotationUtilsTests {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void findAnnotationDeclaringClassForAllScenarios() throws Exception {
|
public void findAnnotationDeclaringClassForAllScenarios() {
|
||||||
// no class-level annotation
|
// no class-level annotation
|
||||||
assertNull(findAnnotationDeclaringClass(Transactional.class, NonAnnotatedInterface.class));
|
assertNull(findAnnotationDeclaringClass(Transactional.class, NonAnnotatedInterface.class));
|
||||||
assertNull(findAnnotationDeclaringClass(Transactional.class, NonAnnotatedClass.class));
|
assertNull(findAnnotationDeclaringClass(Transactional.class, NonAnnotatedClass.class));
|
||||||
@@ -395,7 +402,7 @@ public class AnnotationUtilsTests {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void isAnnotationInheritedForAllScenarios() throws Exception {
|
public void isAnnotationInheritedForAllScenarios() {
|
||||||
// no class-level annotation
|
// no class-level annotation
|
||||||
assertFalse(isAnnotationInherited(Transactional.class, NonAnnotatedInterface.class));
|
assertFalse(isAnnotationInherited(Transactional.class, NonAnnotatedInterface.class));
|
||||||
assertFalse(isAnnotationInherited(Transactional.class, NonAnnotatedClass.class));
|
assertFalse(isAnnotationInherited(Transactional.class, NonAnnotatedClass.class));
|
||||||
@@ -504,7 +511,7 @@ public class AnnotationUtilsTests {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void getDefaultValueFromNonPublicAnnotation() throws Exception {
|
public void getDefaultValueFromNonPublicAnnotation() {
|
||||||
Annotation[] declaredAnnotations = NonPublicAnnotatedClass.class.getDeclaredAnnotations();
|
Annotation[] declaredAnnotations = NonPublicAnnotatedClass.class.getDeclaredAnnotations();
|
||||||
assertEquals(1, declaredAnnotations.length);
|
assertEquals(1, declaredAnnotations.length);
|
||||||
Annotation annotation = declaredAnnotations[0];
|
Annotation annotation = declaredAnnotations[0];
|
||||||
@@ -515,7 +522,7 @@ public class AnnotationUtilsTests {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void getDefaultValueFromAnnotationType() throws Exception {
|
public void getDefaultValueFromAnnotationType() {
|
||||||
assertEquals(Ordered.LOWEST_PRECEDENCE, getDefaultValue(Order.class, VALUE));
|
assertEquals(Ordered.LOWEST_PRECEDENCE, getDefaultValue(Order.class, VALUE));
|
||||||
assertEquals(Ordered.LOWEST_PRECEDENCE, getDefaultValue(Order.class));
|
assertEquals(Ordered.LOWEST_PRECEDENCE, getDefaultValue(Order.class));
|
||||||
}
|
}
|
||||||
@@ -547,7 +554,7 @@ public class AnnotationUtilsTests {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void getRepeatableAnnotationsDeclaredOnClassWithAttributeAliases() throws Exception {
|
public void getRepeatableAnnotationsDeclaredOnClassWithAttributeAliases() {
|
||||||
final List<String> expectedLocations = asList("A", "B");
|
final List<String> expectedLocations = asList("A", "B");
|
||||||
|
|
||||||
Set<ContextConfig> annotations = getRepeatableAnnotations(ConfigHierarchyTestCase.class, ContextConfig.class, null);
|
Set<ContextConfig> annotations = getRepeatableAnnotations(ConfigHierarchyTestCase.class, ContextConfig.class, null);
|
||||||
@@ -1750,6 +1757,18 @@ public class AnnotationUtilsTests {
|
|||||||
public static class SubTransactionalAndOrderedClass extends TransactionalAndOrderedClass {
|
public static class SubTransactionalAndOrderedClass extends TransactionalAndOrderedClass {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public interface InterfaceWithGenericAnnotatedMethod<T> {
|
||||||
|
|
||||||
|
@Order
|
||||||
|
void foo(T t);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class ImplementsInterfaceWithGenericAnnotatedMethod implements InterfaceWithGenericAnnotatedMethod<String> {
|
||||||
|
|
||||||
|
public void foo(String t) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public interface InterfaceWithAnnotatedMethod {
|
public interface InterfaceWithAnnotatedMethod {
|
||||||
|
|
||||||
@Order
|
@Order
|
||||||
|
|||||||
Reference in New Issue
Block a user