diff --git a/spring-core/src/main/java/org/springframework/core/annotation/AnnotatedElementUtils.java b/spring-core/src/main/java/org/springframework/core/annotation/AnnotatedElementUtils.java
index 6acc5622215..e559ffb2dbb 100644
--- a/spring-core/src/main/java/org/springframework/core/annotation/AnnotatedElementUtils.java
+++ b/spring-core/src/main/java/org/springframework/core/annotation/AnnotatedElementUtils.java
@@ -19,8 +19,11 @@ package org.springframework.core.annotation;
import java.lang.annotation.Annotation;
import java.lang.reflect.AnnotatedElement;
import java.lang.reflect.Method;
+import java.util.ArrayList;
+import java.util.Arrays;
import java.util.HashSet;
import java.util.LinkedHashSet;
+import java.util.List;
import java.util.Map;
import java.util.Set;
@@ -71,11 +74,13 @@ import org.springframework.util.MultiValueMap;
*
*
Support for {@code @Inherited}
* Methods following get semantics will honor the contract of
- * Java's {@link java.lang.annotation.Inherited @Inherited} annotation.
- * However, methods following find semantics will ignore the
- * presence of {@code @Inherited} since the find search algorithm
- * manually traverses type and method hierarchies and thereby implicitly
- * supports annotation inheritance without the need for {@code @Inherited}.
+ * Java's {@link java.lang.annotation.Inherited @Inherited} annotation except
+ * that locally declared annotations (including custom composed annotations)
+ * will be favored over inherited annotations. In contrast, methods following
+ * find semantics will completely ignore the presence of
+ * {@code @Inherited} since the find search algorithm manually
+ * traverses type and method hierarchies and thereby implicitly supports
+ * annotation inheritance without the need for {@code @Inherited}.
*
* @author Phillip Webb
* @author Juergen Hoeller
@@ -352,45 +357,8 @@ public class AnnotatedElementUtils {
*/
public static AnnotationAttributes findAnnotationAttributes(AnnotatedElement element, String annotationType,
boolean classValuesAsString, boolean nestedAnnotationsAsMap) {
- return findAnnotationAttributes(element, annotationType, true, true, true, true, classValuesAsString,
- nestedAnnotationsAsMap);
- }
-
- /**
- * Find the first annotation of the specified {@code annotationType} within
- * the annotation hierarchy above the supplied {@code element} and
- * merge that annotation's attributes with matching attributes from
- * annotations in lower levels of the annotation hierarchy.
- *
- * @param element the annotated element; never {@code null}
- * @param annotationType the fully qualified class name of the annotation
- * type to find; never {@code null} or empty
- * @param searchOnInterfaces whether to search on interfaces, if the
- * annotated element is a class
- * @param searchOnSuperclasses whether to search on superclasses, if
- * the annotated element is a class
- * @param searchOnMethodsInInterfaces whether to search on methods in
- * interfaces, if the annotated element is a method
- * @param searchOnMethodsInSuperclasses whether to search on methods
- * in superclasses, if the annotated element is a method
- * @param classValuesAsString whether to convert Class references into
- * Strings or to preserve them as Class references
- * @param nestedAnnotationsAsMap whether to convert nested Annotation
- * instances into {@code AnnotationAttributes} maps or to preserve them
- * as Annotation instances
- * @return the merged {@code AnnotationAttributes}, or {@code null} if
- * not found
- * @since 4.2
- * @see #searchWithFindSemantics
- * @see MergedAnnotationAttributesProcessor
- */
- private static AnnotationAttributes findAnnotationAttributes(AnnotatedElement element, String annotationType,
- boolean searchOnInterfaces, boolean searchOnSuperclasses, boolean searchOnMethodsInInterfaces,
- boolean searchOnMethodsInSuperclasses, boolean classValuesAsString, boolean nestedAnnotationsAsMap) {
-
- return searchWithFindSemantics(element, annotationType, searchOnInterfaces, searchOnSuperclasses,
- searchOnMethodsInInterfaces, searchOnMethodsInSuperclasses, new MergedAnnotationAttributesProcessor(
- annotationType, classValuesAsString, nestedAnnotationsAsMap));
+ return searchWithFindSemantics(element, annotationType, new MergedAnnotationAttributesProcessor(annotationType,
+ classValuesAsString, nestedAnnotationsAsMap));
}
/**
@@ -511,32 +479,28 @@ public class AnnotatedElementUtils {
if (visited.add(element)) {
try {
- // Local annotations: declared OR inherited
- Annotation[] annotations = element.getAnnotations();
- // Search in local annotations
- for (Annotation annotation : annotations) {
- if (!AnnotationUtils.isInJavaLangAnnotationPackage(annotation)
- && (annotation.annotationType().getName().equals(annotationType) || metaDepth > 0)) {
- T result = processor.process(annotation, metaDepth);
- if (result != null) {
- return result;
- }
- }
+ // Start searching within locally declared annotations
+ List declaredAnnotations = Arrays.asList(element.getDeclaredAnnotations());
+ T result = searchWithGetSemanticsInAnnotations(declaredAnnotations, annotationType, processor, visited,
+ metaDepth);
+ if (result != null) {
+ return result;
}
- // Search in meta annotations on local annotations
- for (Annotation annotation : annotations) {
- if (!AnnotationUtils.isInJavaLangAnnotationPackage(annotation)) {
- T result = searchWithGetSemantics(annotation.annotationType(), annotationType, processor,
- visited, metaDepth + 1);
- if (result != null) {
- processor.postProcess(annotation, result);
- return result;
- }
+ List inheritedAnnotations = new ArrayList();
+ for (Annotation annotation : element.getAnnotations()) {
+ if (!declaredAnnotations.contains(annotation)) {
+ inheritedAnnotations.add(annotation);
}
}
+ // Continue searching within inherited annotations
+ result = searchWithGetSemanticsInAnnotations(inheritedAnnotations, annotationType, processor, visited,
+ metaDepth);
+ if (result != null) {
+ return result;
+ }
}
catch (Exception ex) {
AnnotationUtils.logIntrospectionFailure(element, ex);
@@ -545,6 +509,69 @@ public class AnnotatedElementUtils {
return null;
}
+ /**
+ * This method is invoked by
+ * {@link #searchWithGetSemantics(AnnotatedElement, String, Processor, Set, int)}
+ * to perform the actual search within the supplied list of annotations.
+ * This method should be invoked first with locally declared annotations
+ * and then subsequently with inherited annotations, thereby allowing
+ * local annotations to take precedence over inherited annotations.
+ *
+ *
The {@code metaDepth} parameter is explained in the
+ * {@link Processor#process process()} method of the {@link Processor}
+ * API.
+ *
+ * @param annotations the annotations to search in; never {@code null}
+ * @param annotationType the fully qualified class name of the annotation
+ * type to find; never {@code null} or empty
+ * @param processor the processor to delegate to
+ * @param visited the set of annotated elements that have already been visited
+ * @param metaDepth the meta-depth of the annotation
+ * @return the result of the processor, potentially {@code null}
+ */
+ private static T searchWithGetSemanticsInAnnotations(List annotations, String annotationType,
+ Processor processor, Set visited, int metaDepth) {
+
+ // Search in annotations
+ for (Annotation annotation : annotations) {
+ if (!AnnotationUtils.isInJavaLangAnnotationPackage(annotation)
+ && (annotation.annotationType().getName().equals(annotationType) || metaDepth > 0)) {
+ T result = processor.process(annotation, metaDepth);
+ if (result != null) {
+ return result;
+ }
+ }
+ }
+
+ // Recursively search in meta-annotations
+ for (Annotation annotation : annotations) {
+ if (!AnnotationUtils.isInJavaLangAnnotationPackage(annotation)) {
+ T result = searchWithGetSemantics(annotation.annotationType(), annotationType, processor, visited,
+ metaDepth + 1);
+ if (result != null) {
+ processor.postProcess(annotation, result);
+ return result;
+ }
+ }
+ }
+
+ return null;
+ }
+
+ /**
+ * Search for annotations of the specified {@code annotationType} on
+ * the specified {@code element}, following find semantics.
+ *
+ * @param element the annotated element; never {@code null}
+ * @param annotationType the fully qualified class name of the annotation
+ * type to find; never {@code null} or empty
+ * @param processor the processor to delegate to
+ * @return the result of the processor, potentially {@code null}
+ */
+ private static T searchWithFindSemantics(AnnotatedElement element, String annotationType, Processor processor) {
+ return searchWithFindSemantics(element, annotationType, true, true, true, true, processor);
+ }
+
/**
* Search for annotations of the specified {@code annotationType} on
* the specified {@code element}, following find semantics.
diff --git a/spring-core/src/test/java/org/springframework/core/annotation/AnnotatedElementUtilsTests.java b/spring-core/src/test/java/org/springframework/core/annotation/AnnotatedElementUtilsTests.java
index 28da1783eb0..1f53718edcc 100644
--- a/spring-core/src/test/java/org/springframework/core/annotation/AnnotatedElementUtilsTests.java
+++ b/spring-core/src/test/java/org/springframework/core/annotation/AnnotatedElementUtilsTests.java
@@ -23,16 +23,15 @@ import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import java.lang.reflect.Method;
-import java.util.Arrays;
import java.util.Set;
import java.util.stream.Collectors;
-import org.junit.Ignore;
import org.junit.Test;
import org.springframework.stereotype.Component;
import org.springframework.util.MultiValueMap;
+import static java.util.Arrays.*;
import static org.junit.Assert.*;
import static org.springframework.core.annotation.AnnotatedElementUtils.*;
@@ -45,8 +44,10 @@ import static org.springframework.core.annotation.AnnotatedElementUtils.*;
*/
public class AnnotatedElementUtilsTests {
+ private static final String TX_NAME = Transactional.class.getName();
+
private Set names(Class>... classes) {
- return Arrays.stream(classes).map(clazz -> clazz.getName()).collect(Collectors.toSet());
+ return stream(classes).map(clazz -> clazz.getName()).collect(Collectors.toSet());
}
@Test
@@ -62,13 +63,14 @@ public class AnnotatedElementUtilsTests {
@Test
public void getMetaAnnotationTypesOnClassWithMetaDepth2() {
- Set names = getMetaAnnotationTypes(ComposedTransactionalComponentClass.class, ComposedTransactionalComponent.class);
+ Set names = getMetaAnnotationTypes(ComposedTransactionalComponentClass.class,
+ ComposedTransactionalComponent.class);
assertEquals(names(TransactionalComponent.class, Transactional.class, Component.class), names);
}
@Test
public void hasMetaAnnotationTypesOnNonAnnotatedClass() {
- assertFalse(hasMetaAnnotationTypes(NonAnnotatedClass.class, Transactional.class.getName()));
+ assertFalse(hasMetaAnnotationTypes(NonAnnotatedClass.class, TX_NAME));
}
@Test
@@ -78,20 +80,21 @@ public class AnnotatedElementUtilsTests {
@Test
public void hasMetaAnnotationTypesOnClassWithMetaDepth1() {
- assertTrue(hasMetaAnnotationTypes(TransactionalComponentClass.class, Transactional.class.getName()));
+ assertTrue(hasMetaAnnotationTypes(TransactionalComponentClass.class, TX_NAME));
assertTrue(hasMetaAnnotationTypes(TransactionalComponentClass.class, Component.class.getName()));
}
@Test
public void hasMetaAnnotationTypesOnClassWithMetaDepth2() {
- assertTrue(hasMetaAnnotationTypes(ComposedTransactionalComponentClass.class, Transactional.class.getName()));
+ assertTrue(hasMetaAnnotationTypes(ComposedTransactionalComponentClass.class, TX_NAME));
assertTrue(hasMetaAnnotationTypes(ComposedTransactionalComponentClass.class, Component.class.getName()));
- assertFalse(hasMetaAnnotationTypes(ComposedTransactionalComponentClass.class, ComposedTransactionalComponent.class.getName()));
+ assertFalse(hasMetaAnnotationTypes(ComposedTransactionalComponentClass.class,
+ ComposedTransactionalComponent.class.getName()));
}
@Test
public void isAnnotatedOnNonAnnotatedClass() {
- assertFalse(isAnnotated(NonAnnotatedClass.class, Transactional.class.getName()));
+ assertFalse(isAnnotated(NonAnnotatedClass.class, TX_NAME));
}
@Test
@@ -107,35 +110,49 @@ public class AnnotatedElementUtilsTests {
@Test
public void isAnnotatedOnClassWithMetaDepth1() {
- assertTrue(isAnnotated(TransactionalComponentClass.class, Transactional.class.getName()));
+ assertTrue(isAnnotated(TransactionalComponentClass.class, TX_NAME));
assertTrue(isAnnotated(TransactionalComponentClass.class, Component.class.getName()));
}
@Test
public void isAnnotatedOnClassWithMetaDepth2() {
- assertTrue(isAnnotated(ComposedTransactionalComponentClass.class, Transactional.class.getName()));
+ assertTrue(isAnnotated(ComposedTransactionalComponentClass.class, TX_NAME));
assertTrue(isAnnotated(ComposedTransactionalComponentClass.class, Component.class.getName()));
- assertTrue(isAnnotated(ComposedTransactionalComponentClass.class, ComposedTransactionalComponent.class.getName()));
+ assertTrue(isAnnotated(ComposedTransactionalComponentClass.class,
+ ComposedTransactionalComponent.class.getName()));
}
@Test
public void getAllAnnotationAttributesOnNonAnnotatedClass() {
- assertNull(getAllAnnotationAttributes(NonAnnotatedClass.class, Transactional.class.getName()));
+ assertNull(getAllAnnotationAttributes(NonAnnotatedClass.class, TX_NAME));
}
@Test
public void getAllAnnotationAttributesOnClassWithLocalAnnotation() {
- MultiValueMap attributes = getAllAnnotationAttributes(TxConfig.class, Transactional.class.getName());
+ MultiValueMap attributes = getAllAnnotationAttributes(TxConfig.class, TX_NAME);
assertNotNull("Annotation attributes map for @Transactional on TxConfig", attributes);
- assertEquals("value for TxConfig.", Arrays.asList("TxConfig"), attributes.get("value"));
+ assertEquals("value for TxConfig.", asList("TxConfig"), attributes.get("value"));
+ }
+
+ @Test
+ public void getAllAnnotationAttributesOnClassWithLocalComposedAnnotationAndInheritedAnnotation() {
+ MultiValueMap attributes = getAllAnnotationAttributes(SubClassWithInheritedAnnotation.class, TX_NAME);
+ assertNotNull("Annotation attributes map for @Transactional on SubClassWithInheritedAnnotation", attributes);
+ assertEquals(asList("composed2", "transactionManager"), attributes.get("qualifier"));
+ }
+
+ @Test
+ public void getAllAnnotationAttributesFavorsInheritedAnnotationsOverMoreLocallyDeclaredComposedAnnotations() {
+ MultiValueMap attributes = getAllAnnotationAttributes(SubSubClassWithInheritedAnnotation.class, TX_NAME);
+ assertNotNull("Annotation attributes map for @Transactional on SubSubClassWithInheritedAnnotation", attributes);
+ assertEquals(asList("transactionManager"), attributes.get("qualifier"));
}
@Test
public void getAllAnnotationAttributesFavorsInheritedComposedAnnotationsOverMoreLocallyDeclaredComposedAnnotations() {
- MultiValueMap attributes = getAllAnnotationAttributes(SubSubClassWithInheritedComposedAnnotation.class,
- Transactional.class.getName());
+ MultiValueMap attributes = getAllAnnotationAttributes( SubSubClassWithInheritedComposedAnnotation.class, TX_NAME);
assertNotNull("Annotation attributes map for @Transactional on SubSubClassWithInheritedComposedAnnotation", attributes);
- assertEquals(Arrays.asList("composed1"), attributes.get("qualifier"));
+ assertEquals(asList("composed1"), attributes.get("qualifier"));
}
/**
@@ -149,9 +166,9 @@ public class AnnotatedElementUtilsTests {
*/
@Test
public void getAllAnnotationAttributesOnClassWithLocalAnnotationThatShadowsAnnotationFromSuperclass() {
- MultiValueMap attributes = getAllAnnotationAttributes(DerivedTxConfig.class, Transactional.class.getName());
+ MultiValueMap attributes = getAllAnnotationAttributes(DerivedTxConfig.class, TX_NAME);
assertNotNull("Annotation attributes map for @Transactional on DerivedTxConfig", attributes);
- assertEquals("value for DerivedTxConfig.", Arrays.asList("DerivedTxConfig"), attributes.get("value"));
+ assertEquals("value for DerivedTxConfig.", asList("DerivedTxConfig"), attributes.get("value"));
}
/**
@@ -161,17 +178,15 @@ public class AnnotatedElementUtilsTests {
*/
@Test
public void getAllAnnotationAttributesOnClassWithMultipleComposedAnnotations() {
- MultiValueMap attributes = getAllAnnotationAttributes(TxFromMultipleComposedAnnotations.class,
- Transactional.class.getName());
+ MultiValueMap attributes = getAllAnnotationAttributes(TxFromMultipleComposedAnnotations.class, TX_NAME);
assertNotNull("Annotation attributes map for @Transactional on TxFromMultipleComposedAnnotations", attributes);
- assertEquals("value for TxFromMultipleComposedAnnotations.", Arrays.asList("TxComposed1", "TxComposed2"),
- attributes.get("value"));
+ assertEquals("value for TxFromMultipleComposedAnnotations.", asList("TxComposed1", "TxComposed2"), attributes.get("value"));
}
@Test
public void getAnnotationAttributesOnClassWithLocalAnnotation() {
Class> element = TxConfig.class;
- String name = Transactional.class.getName();
+ String name = TX_NAME;
AnnotationAttributes attributes = getAnnotationAttributes(element, name);
assertNotNull("Annotation attributes for @Transactional on TxConfig", attributes);
assertEquals("value for TxConfig.", "TxConfig", attributes.getString("value"));
@@ -182,7 +197,7 @@ public class AnnotatedElementUtilsTests {
@Test
public void getAnnotationAttributesOnClassWithLocalAnnotationThatShadowsAnnotationFromSuperclass() {
Class> element = DerivedTxConfig.class;
- String name = Transactional.class.getName();
+ String name = TX_NAME;
AnnotationAttributes attributes = getAnnotationAttributes(element, name);
assertNotNull("Annotation attributes for @Transactional on DerivedTxConfig", attributes);
assertEquals("value for DerivedTxConfig.", "DerivedTxConfig", attributes.getString("value"));
@@ -192,58 +207,59 @@ public class AnnotatedElementUtilsTests {
@Test
public void getAnnotationAttributesOnMetaCycleAnnotatedClassWithMissingTargetMetaAnnotation() {
- AnnotationAttributes attributes = getAnnotationAttributes(MetaCycleAnnotatedClass.class,
- Transactional.class.getName());
+ AnnotationAttributes attributes = getAnnotationAttributes(MetaCycleAnnotatedClass.class, TX_NAME);
assertNull("Should not find annotation attributes for @Transactional on MetaCycleAnnotatedClass", attributes);
}
+ @Test
+ public void getAnnotationAttributesFavorsLocalComposedAnnotationOverInheritedAnnotation() {
+ Class> element = SubClassWithInheritedAnnotation.class;
+ String name = TX_NAME;
+ AnnotationAttributes attributes = getAnnotationAttributes(element, name);
+ assertNotNull("AnnotationAttributes for @Transactional on SubClassWithInheritedAnnotation", attributes);
+ // Verify contracts between utility methods:
+ assertTrue(isAnnotated(element, name));
+ assertTrue("readOnly flag for SubClassWithInheritedAnnotation.", attributes.getBoolean("readOnly"));
+ }
+
@Test
public void getAnnotationAttributesFavorsInheritedAnnotationsOverMoreLocallyDeclaredComposedAnnotations() {
Class> element = SubSubClassWithInheritedAnnotation.class;
- String name = Transactional.class.getName();
+ String name = TX_NAME;
AnnotationAttributes attributes = getAnnotationAttributes(element, name);
assertNotNull("AnnotationAttributes for @Transactional on SubSubClassWithInheritedAnnotation", attributes);
// Verify contracts between utility methods:
assertTrue(isAnnotated(element, name));
-
- // TODO [SPR-11598] Set expected to true.
- boolean expected = false;
- assertEquals("readOnly flag for SubSubClassWithInheritedAnnotation.", expected, attributes.getBoolean("readOnly"));
+ assertFalse("readOnly flag for SubSubClassWithInheritedAnnotation.", attributes.getBoolean("readOnly"));
}
@Test
public void getAnnotationAttributesFavorsInheritedComposedAnnotationsOverMoreLocallyDeclaredComposedAnnotations() {
Class> element = SubSubClassWithInheritedComposedAnnotation.class;
- String name = Transactional.class.getName();
+ String name = TX_NAME;
AnnotationAttributes attributes = getAnnotationAttributes(element, name);
assertNotNull("AnnotationAttributtes for @Transactional on SubSubClassWithInheritedComposedAnnotation.", attributes);
// Verify contracts between utility methods:
assertTrue(isAnnotated(element, name));
-
- // TODO [SPR-11598] Set expected to true.
- boolean expected = false;
- assertEquals("readOnly flag for SubSubClassWithInheritedComposedAnnotation.", expected,
- attributes.getBoolean("readOnly"));
+ assertFalse("readOnly flag for SubSubClassWithInheritedComposedAnnotation.", attributes.getBoolean("readOnly"));
}
- // TODO [SPR-11598] Enable test.
- @Ignore("Disabled until SPR-11598 is resolved")
@Test
public void getAnnotationAttributesFromInterfaceImplementedBySuperclass() {
Class> element = ConcreteClassWithInheritedAnnotation.class;
- String name = Transactional.class.getName();
+ String name = TX_NAME;
AnnotationAttributes attributes = getAnnotationAttributes(element, name);
- assertNotNull("Should find @Transactional on ConcreteClassWithInheritedAnnotation", attributes);
+ assertNull("Should not find @Transactional on ConcreteClassWithInheritedAnnotation", attributes);
// Verify contracts between utility methods:
- assertTrue(isAnnotated(element, name));
+ assertFalse(isAnnotated(element, name));
}
@Test
public void getAnnotationAttributesOnInheritedAnnotationInterface() {
Class> element = InheritedAnnotationInterface.class;
- String name = Transactional.class.getName();
+ String name = TX_NAME;
AnnotationAttributes attributes = getAnnotationAttributes(element, name);
- assertNotNull("Should get @Transactional on InheritedAnnotationInterface", attributes);
+ assertNotNull("Should find @Transactional on InheritedAnnotationInterface", attributes);
// Verify contracts between utility methods:
assertTrue(isAnnotated(element, name));
}
@@ -253,7 +269,7 @@ public class AnnotatedElementUtilsTests {
Class> element = NonInheritedAnnotationInterface.class;
String name = Order.class.getName();
AnnotationAttributes attributes = getAnnotationAttributes(element, name);
- assertNotNull("Should get @Order on NonInheritedAnnotationInterface", attributes);
+ assertNotNull("Should find @Order on NonInheritedAnnotationInterface", attributes);
// Verify contracts between utility methods:
assertTrue(isAnnotated(element, name));
}
@@ -322,7 +338,7 @@ public class AnnotatedElementUtilsTests {
public void findAnnotationAttributesInheritedFromBridgedMethod() throws NoSuchMethodException {
Method method = ConcreteClassWithInheritedAnnotation.class.getMethod("handleParameterized", String.class);
AnnotationAttributes attributes = findAnnotationAttributes(method, Transactional.class);
- assertNull("Should not find @Transactional on bridged ConcreteClassWithInheritedAnnotation.handleParameterized() method", attributes);
+ assertNull("Should not find @Transactional on bridged ConcreteClassWithInheritedAnnotation.handleParameterized()", attributes);
}
/**
@@ -390,7 +406,7 @@ public class AnnotatedElementUtilsTests {
// -------------------------------------------------------------------------
@Retention(RetentionPolicy.RUNTIME)
- @Target({ElementType.TYPE, ElementType.METHOD})
+ @Target({ ElementType.TYPE, ElementType.METHOD })
@Documented
@Inherited
@interface Transactional {
@@ -559,7 +575,6 @@ public class AnnotatedElementUtilsTests {
}
}
-
@Transactional
public static interface InheritedAnnotationInterface {
}
diff --git a/spring-core/src/test/java/org/springframework/core/annotation/AnnotationUtilsTests.java b/spring-core/src/test/java/org/springframework/core/annotation/AnnotationUtilsTests.java
index d34e0c20e9c..cf4f7543d5b 100644
--- a/spring-core/src/test/java/org/springframework/core/annotation/AnnotationUtilsTests.java
+++ b/spring-core/src/test/java/org/springframework/core/annotation/AnnotationUtilsTests.java
@@ -153,27 +153,24 @@ public class AnnotationUtilsTests {
/** @since 4.1.2 */
@Test
- public void findClassAnnotationFavorsLocalMetaAnnotationsOverInterfaces() {
- Component component = AnnotationUtils.findAnnotation(
- ClassWithLocalMetaAnnotationAndMetaAnnotatedInterface.class, Component.class);
+ public void findClassAnnotationFavorsMoreLocallyDeclaredComposedAnnotationsOverAnnotationsOnInterfaces() {
+ Component component = AnnotationUtils.findAnnotation(ClassWithLocalMetaAnnotationAndMetaAnnotatedInterface.class, Component.class);
assertNotNull(component);
assertEquals("meta2", component.value());
}
/** @since 4.0.3 */
@Test
- public void findClassAnnotationFavorsInheritedAnnotationsOverMoreLocallyDeclaredComposedAnnotations() {
- Transactional transactional = AnnotationUtils.findAnnotation(
- SubSubClassWithInheritedAnnotation.class, Transactional.class);
+ public void findClassAnnotationFavorsMoreLocallyDeclaredComposedAnnotationsOverInheritedAnnotations() {
+ Transactional transactional = AnnotationUtils.findAnnotation(SubSubClassWithInheritedAnnotation.class, Transactional.class);
assertNotNull(transactional);
assertTrue("readOnly flag for SubSubClassWithInheritedAnnotation", transactional.readOnly());
}
/** @since 4.0.3 */
@Test
- public void findClassAnnotationFavorsInheritedComposedAnnotationsOverMoreLocallyDeclaredComposedAnnotations() {
- Component component = AnnotationUtils.findAnnotation(
- SubSubClassWithInheritedMetaAnnotation.class, Component.class);
+ public void findClassAnnotationFavorsMoreLocallyDeclaredComposedAnnotationsOverInheritedComposedAnnotations() {
+ Component component = AnnotationUtils.findAnnotation(SubSubClassWithInheritedMetaAnnotation.class, Component.class);
assertNotNull(component);
assertEquals("meta2", component.value());
}