Find annotations on implemented generic superclass methods as well

Includes Java 8 getDeclaredAnnotation shortcut for lookup on Class.

Issue: SPR-17146
This commit is contained in:
Juergen Hoeller
2018-08-08 23:52:47 +02:00
parent fa72186e28
commit 4521a79b2d
4 changed files with 92 additions and 78 deletions

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2002-2017 the original author or authors.
* Copyright 2002-2018 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -525,19 +525,11 @@ public class AnnotatedElementUtilsTests {
assertNotNull("Should find @Transactional on ConcreteClassWithInheritedAnnotation.handle() method", attributes);
}
/**
* <p>{@code AbstractClassWithInheritedAnnotation} declares {@code handleParameterized(T)}; whereas,
* {@code ConcreteClassWithInheritedAnnotation} declares {@code handleParameterized(String)}.
* <p>As of Spring 4.2, {@code AnnotatedElementUtils.processWithFindSemantics()} does not resolve an
* <em>equivalent</em> method in {@code AbstractClassWithInheritedAnnotation} for the <em>bridged</em>
* {@code handleParameterized(String)} method.
* @since 4.2
*/
@Test
public void findMergedAnnotationAttributesInheritedFromBridgedMethod() throws NoSuchMethodException {
Method method = ConcreteClassWithInheritedAnnotation.class.getMethod("handleParameterized", String.class);
AnnotationAttributes attributes = findMergedAnnotationAttributes(method, Transactional.class);
assertNull("Should not find @Transactional on bridged ConcreteClassWithInheritedAnnotation.handleParameterized()", attributes);
assertNotNull("Should find @Transactional on bridged ConcreteClassWithInheritedAnnotation.handleParameterized()", attributes);
}
/**
@@ -546,7 +538,7 @@ public class AnnotatedElementUtilsTests {
* @since 4.2
*/
@Test
public void findMergedAnnotationAttributesFromBridgeMethod() throws NoSuchMethodException {
public void findMergedAnnotationAttributesFromBridgeMethod() {
Method[] methods = StringGenericParameter.class.getMethods();
Method bridgeMethod = null;
Method bridgedMethod = null;
@@ -733,6 +725,20 @@ public class AnnotatedElementUtilsTests {
assertEquals(1, allMergedAnnotations.size());
}
@Test // SPR-16060
public void findMethodAnnotationFromGenericInterface() throws Exception {
Method method = ImplementsInterfaceWithGenericAnnotatedMethod.class.getMethod("foo", String.class);
Order order = findMergedAnnotation(method, Order.class);
assertNotNull(order);
}
@Test // SPR-17146
public void findMethodAnnotationFromGenericSuperclass() throws Exception {
Method method = ExtendsBaseClassWithGenericAnnotatedMethod.class.getMethod("foo", String.class);
Order order = findMergedAnnotation(method, Order.class);
assertNotNull(order);
}
// -------------------------------------------------------------------------

View File

@@ -167,9 +167,7 @@ public class AnnotationUtilsTests {
assertNull(bridgedMethod.getAnnotation(Order.class));
assertNull(getAnnotation(bridgedMethod, Order.class));
// AnnotationUtils.findAnnotation(Method, Class<A>) will not find an annotation on
// the bridge method for a bridged method.
assertNull(findAnnotation(bridgedMethod, Order.class));
assertNotNull(findAnnotation(bridgedMethod, Order.class));
assertNotNull(bridgedMethod.getAnnotation(Transactional.class));
assertNotNull(getAnnotation(bridgedMethod, Transactional.class));
@@ -190,6 +188,13 @@ public class AnnotationUtilsTests {
assertNotNull(order);
}
@Test // SPR-17146
public void findMethodAnnotationFromGenericSuperclass() throws Exception {
Method method = ExtendsBaseClassWithGenericAnnotatedMethod.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");
@@ -204,7 +209,7 @@ public class AnnotationUtilsTests {
assertNotNull(order);
}
/** @since 4.1.2 */
// @since 4.1.2
@Test
public void findClassAnnotationFavorsMoreLocallyDeclaredComposedAnnotationsOverAnnotationsOnInterfaces() {
Component component = findAnnotation(ClassWithLocalMetaAnnotationAndMetaAnnotatedInterface.class, Component.class);
@@ -212,7 +217,7 @@ public class AnnotationUtilsTests {
assertEquals("meta2", component.value());
}
/** @since 4.0.3 */
// @since 4.0.3
@Test
public void findClassAnnotationFavorsMoreLocallyDeclaredComposedAnnotationsOverInheritedAnnotations() {
Transactional transactional = findAnnotation(SubSubClassWithInheritedAnnotation.class, Transactional.class);
@@ -220,7 +225,7 @@ public class AnnotationUtilsTests {
assertTrue("readOnly flag for SubSubClassWithInheritedAnnotation", transactional.readOnly());
}
/** @since 4.0.3 */
// @since 4.0.3
@Test
public void findClassAnnotationFavorsMoreLocallyDeclaredComposedAnnotationsOverInheritedComposedAnnotations() {
Component component = findAnnotation(SubSubClassWithInheritedMetaAnnotation.class, Component.class);
@@ -1762,18 +1767,6 @@ 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
@@ -1806,6 +1799,30 @@ public class AnnotationUtilsTests {
}
}
public interface InterfaceWithGenericAnnotatedMethod<T> {
@Order
void foo(T t);
}
public static class ImplementsInterfaceWithGenericAnnotatedMethod implements InterfaceWithGenericAnnotatedMethod<String> {
public void foo(String t) {
}
}
public static abstract class BaseClassWithGenericAnnotatedMethod<T> {
@Order
abstract void foo(T t);
}
public static class ExtendsBaseClassWithGenericAnnotatedMethod extends BaseClassWithGenericAnnotatedMethod<String> {
public void foo(String t) {
}
}
@Retention(RetentionPolicy.RUNTIME)
@Inherited
@interface MyRepeatableContainer {