Find annotations on implemented generic interface methods as well
Issue: SPR-16060
This commit is contained in:
		
							parent
							
								
									c77dbbb1e6
								
							
						
					
					
						commit
						23d4862017
					
				| 
						 | 
				
			
			@ -39,6 +39,7 @@ import org.apache.commons.logging.Log;
 | 
			
		|||
import org.apache.commons.logging.LogFactory;
 | 
			
		||||
 | 
			
		||||
import org.springframework.core.BridgeMethodResolver;
 | 
			
		||||
import org.springframework.core.ResolvableType;
 | 
			
		||||
import org.springframework.lang.Nullable;
 | 
			
		||||
import org.springframework.util.Assert;
 | 
			
		||||
import org.springframework.util.ClassUtils;
 | 
			
		||||
| 
						 | 
				
			
			@ -588,8 +589,7 @@ public abstract class AnnotationUtils {
 | 
			
		|||
			Set<Method> annotatedMethods = getAnnotatedMethodsInBaseType(ifc);
 | 
			
		||||
			if (!annotatedMethods.isEmpty()) {
 | 
			
		||||
				for (Method annotatedMethod : annotatedMethods) {
 | 
			
		||||
					if (annotatedMethod.getName().equals(method.getName()) &&
 | 
			
		||||
							Arrays.equals(annotatedMethod.getParameterTypes(), method.getParameterTypes())) {
 | 
			
		||||
					if (isOverride(method, annotatedMethod)) {
 | 
			
		||||
						A annotation = getAnnotation(annotatedMethod, annotationType);
 | 
			
		||||
						if (annotation != null) {
 | 
			
		||||
							return annotation;
 | 
			
		||||
| 
						 | 
				
			
			@ -647,6 +647,23 @@ public abstract class AnnotationUtils {
 | 
			
		|||
		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
 | 
			
		||||
	 * supplied {@link Class}, traversing its interfaces, annotations, and
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -178,6 +178,13 @@ public class AnnotationUtilsTests {
 | 
			
		|||
		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
 | 
			
		||||
	public void findMethodAnnotationFromInterfaceOnSuper() throws Exception {
 | 
			
		||||
		Method method = SubOfImplementsInterfaceWithAnnotatedMethod.class.getMethod("foo");
 | 
			
		||||
| 
						 | 
				
			
			@ -286,7 +293,7 @@ public class AnnotationUtilsTests {
 | 
			
		|||
	}
 | 
			
		||||
 | 
			
		||||
	@Test
 | 
			
		||||
	public void findAnnotationDeclaringClassForAllScenarios() throws Exception {
 | 
			
		||||
	public void findAnnotationDeclaringClassForAllScenarios() {
 | 
			
		||||
		// no class-level annotation
 | 
			
		||||
		assertNull(findAnnotationDeclaringClass(Transactional.class, NonAnnotatedInterface.class));
 | 
			
		||||
		assertNull(findAnnotationDeclaringClass(Transactional.class, NonAnnotatedClass.class));
 | 
			
		||||
| 
						 | 
				
			
			@ -395,7 +402,7 @@ public class AnnotationUtilsTests {
 | 
			
		|||
	}
 | 
			
		||||
 | 
			
		||||
	@Test
 | 
			
		||||
	public void isAnnotationInheritedForAllScenarios() throws Exception {
 | 
			
		||||
	public void isAnnotationInheritedForAllScenarios() {
 | 
			
		||||
		// no class-level annotation
 | 
			
		||||
		assertFalse(isAnnotationInherited(Transactional.class, NonAnnotatedInterface.class));
 | 
			
		||||
		assertFalse(isAnnotationInherited(Transactional.class, NonAnnotatedClass.class));
 | 
			
		||||
| 
						 | 
				
			
			@ -504,7 +511,7 @@ public class AnnotationUtilsTests {
 | 
			
		|||
	}
 | 
			
		||||
 | 
			
		||||
	@Test
 | 
			
		||||
	public void getDefaultValueFromNonPublicAnnotation() throws Exception {
 | 
			
		||||
	public void getDefaultValueFromNonPublicAnnotation() {
 | 
			
		||||
		Annotation[] declaredAnnotations = NonPublicAnnotatedClass.class.getDeclaredAnnotations();
 | 
			
		||||
		assertEquals(1, declaredAnnotations.length);
 | 
			
		||||
		Annotation annotation = declaredAnnotations[0];
 | 
			
		||||
| 
						 | 
				
			
			@ -515,7 +522,7 @@ public class AnnotationUtilsTests {
 | 
			
		|||
	}
 | 
			
		||||
 | 
			
		||||
	@Test
 | 
			
		||||
	public void getDefaultValueFromAnnotationType() throws Exception {
 | 
			
		||||
	public void getDefaultValueFromAnnotationType() {
 | 
			
		||||
		assertEquals(Ordered.LOWEST_PRECEDENCE, getDefaultValue(Order.class, VALUE));
 | 
			
		||||
		assertEquals(Ordered.LOWEST_PRECEDENCE, getDefaultValue(Order.class));
 | 
			
		||||
	}
 | 
			
		||||
| 
						 | 
				
			
			@ -547,7 +554,7 @@ public class AnnotationUtilsTests {
 | 
			
		|||
	}
 | 
			
		||||
 | 
			
		||||
	@Test
 | 
			
		||||
	public void getRepeatableAnnotationsDeclaredOnClassWithAttributeAliases() throws Exception {
 | 
			
		||||
	public void getRepeatableAnnotationsDeclaredOnClassWithAttributeAliases() {
 | 
			
		||||
		final List<String> expectedLocations = asList("A", "B");
 | 
			
		||||
 | 
			
		||||
		Set<ContextConfig> annotations = getRepeatableAnnotations(ConfigHierarchyTestCase.class, ContextConfig.class, null);
 | 
			
		||||
| 
						 | 
				
			
			@ -1750,6 +1757,18 @@ public class AnnotationUtilsTests {
 | 
			
		|||
	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 {
 | 
			
		||||
 | 
			
		||||
		@Order
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
		Reference in New Issue