Do not inspect meta-annotations on Java annotations

This commit introduces a new isInJavaLangAnnotationPackage(Annotation)
method in AnnotationUtils. This method is now used in AnnotationUtils,
AnnotatedElementUtils, and MetaAnnotationUtils to ensure that search
algorithms do no search for meta-annotations on annotations in the
"java.lang.annotation" package.

The following are some empirical results from this change:

- The number of times that the findAnnotation(Class,Class,Set) method in
  AnnotationUtils is recursively invoked while executing
  AnnotationUtilsTests drops from 51 to 29.

- The number of times that the process(AnnotatedElement) method in
  AnnotationUtils.AnnotationCollector is recursively invoked while
  executing AnnotationUtilsTests.getRepeatableFromMethod() drops
  from 16 to 2.

- The number of times that the doProcess() method in
  AnnotatedElementUtils is recursively invoked while executing the
  "getAnnotationAttributes() On MetaCycleAnnotatedClass with missing
  target meta-annotation" test in AnnotatedElementUtilsTests drops
  from 23 to 5.

- The number of times that the findAnnotationDescriptor(Class,Set,Class)
  method in MetaAnnotationUtils is recursively invoked while executing
  the "findAnnotationDescriptor() on MetaCycleAnnotatedClass with
  missing target meta-annotation" test in MetaAnnotationUtilsTests drops
  from 16 to 8.

Issue: SPR-11483
This commit is contained in:
Sam Brannen
2014-02-25 21:41:59 +01:00
parent 651e0a44fb
commit 979c483384
6 changed files with 92 additions and 10 deletions

View File

@@ -16,9 +16,12 @@
package org.springframework.core.annotation;
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Inherited;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import org.junit.Test;
@@ -32,6 +35,13 @@ import static org.junit.Assert.*;
*/
public class AnnotatedElementUtilsTests {
@Test
public void getAnnotationAttributesOnMetaCycleAnnotatedClassWithMissingTargetMetaAnnotation() {
AnnotationAttributes attributes = AnnotatedElementUtils.getAnnotationAttributes(MetaCycleAnnotatedClass.class,
Transactional.class.getName());
assertNull("Should not find annotation attributes for @Transactional on MetaCycleAnnotatedClass", attributes);
}
@Test
public void getAnnotationAttributesFavorsInheritedAnnotationsOverMoreLocallyDeclaredComposedAnnotations() {
AnnotationAttributes attributes = AnnotatedElementUtils.getAnnotationAttributes(
@@ -61,7 +71,34 @@ public class AnnotatedElementUtilsTests {
// -------------------------------------------------------------------------
@MetaCycle3
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.ANNOTATION_TYPE)
@Documented
@interface MetaCycle1 {
}
@MetaCycle1
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.ANNOTATION_TYPE)
@Documented
@interface MetaCycle2 {
}
@MetaCycle2
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@Documented
@interface MetaCycle3 {
}
@MetaCycle3
static class MetaCycleAnnotatedClass {
}
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@Documented
@Inherited
@interface Transactional {
@@ -70,12 +107,16 @@ public class AnnotatedElementUtilsTests {
@Transactional
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@Documented
@Inherited
@interface Composed1 {
}
@Transactional(readOnly = true)
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@Documented
@interface Composed2 {
}

View File

@@ -362,6 +362,13 @@ public class AnnotationUtilsTests {
assertNotNull(order);
}
@Test
public void findRepeatableAnnotationOnComposedAnnotation() {
Repeatable repeatable = findAnnotation(MyRepeatableMeta.class, Repeatable.class);
assertNotNull(repeatable);
assertEquals(MyRepeatableContainer.class, repeatable.value());
}
@Test
public void getRepeatableFromMethod() throws Exception {
Method method = InterfaceWithRepeated.class.getMethod("foo");