Skip to content

Commit 3037277

Browse files
committed
Minimize reflective interaction with annotation instances during retrieval
Issue: SPR-15387
1 parent aa3573b commit 3037277

File tree

4 files changed

+92
-75
lines changed

4 files changed

+92
-75
lines changed

spring-core/src/main/java/org/springframework/core/annotation/AnnotatedElementUtils.java

Lines changed: 46 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -427,10 +427,10 @@ public static <A extends Annotation> A getMergedAnnotation(AnnotatedElement elem
427427
* single annotation and within annotation hierarchies.
428428
* <p>This method follows <em>get semantics</em> as described in the
429429
* {@linkplain AnnotatedElementUtils class-level javadoc}.
430-
* @param element the annotated element; never {@code null}
431-
* @param annotationType the annotation type to find; never {@code null}
432-
* @return the set of all merged, synthesized {@code Annotations} found, or an empty
433-
* set if none were found
430+
* @param element the annotated element (never {@code null})
431+
* @param annotationType the annotation type to find (never {@code null})
432+
* @return the set of all merged, synthesized {@code Annotations} found,
433+
* or an empty set if none were found
434434
* @since 4.3
435435
* @see #getMergedAnnotation(AnnotatedElement, Class)
436436
* @see #getAllAnnotationAttributes(AnnotatedElement, String)
@@ -460,10 +460,10 @@ public static <A extends Annotation> Set<A> getAllMergedAnnotations(AnnotatedEle
460460
* single annotation and within annotation hierarchies.
461461
* <p>This method follows <em>get semantics</em> as described in the
462462
* {@linkplain AnnotatedElementUtils class-level javadoc}.
463-
* @param element the annotated element; never {@code null}
464-
* @param annotationType the annotation type to find; never {@code null}
465-
* @return the set of all merged repeatable {@code Annotations} found, or an empty
466-
* set if none were found
463+
* @param element the annotated element (never {@code null})
464+
* @param annotationType the annotation type to find (never {@code null})
465+
* @return the set of all merged repeatable {@code Annotations} found,
466+
* or an empty set if none were found
467467
* @since 4.3
468468
* @see #getMergedAnnotation(AnnotatedElement, Class)
469469
* @see #getAllMergedAnnotations(AnnotatedElement, Class)
@@ -488,13 +488,13 @@ public static <A extends Annotation> Set<A> getMergedRepeatableAnnotations(Annot
488488
* single annotation and within annotation hierarchies.
489489
* <p>This method follows <em>get semantics</em> as described in the
490490
* {@linkplain AnnotatedElementUtils class-level javadoc}.
491-
* @param element the annotated element; never {@code null}
492-
* @param annotationType the annotation type to find; never {@code null}
491+
* @param element the annotated element (never {@code null})
492+
* @param annotationType the annotation type to find (never {@code null})
493493
* @param containerType the type of the container that holds the annotations;
494494
* may be {@code null} if the container type should be looked up via
495495
* {@link java.lang.annotation.Repeatable}
496-
* @return the set of all merged repeatable {@code Annotations} found, or an empty
497-
* set if none were found
496+
* @return the set of all merged repeatable {@code Annotations} found,
497+
* or an empty set if none were found
498498
* @since 4.3
499499
* @see #getMergedAnnotation(AnnotatedElement, Class)
500500
* @see #getAllMergedAnnotations(AnnotatedElement, Class)
@@ -724,10 +724,10 @@ public static <A extends Annotation> A findMergedAnnotation(AnnotatedElement ele
724724
* single annotation and within annotation hierarchies.
725725
* <p>This method follows <em>find semantics</em> as described in the
726726
* {@linkplain AnnotatedElementUtils class-level javadoc}.
727-
* @param element the annotated element; never {@code null}
728-
* @param annotationType the annotation type to find; never {@code null}
729-
* @return the set of all merged, synthesized {@code Annotations} found, or an empty
730-
* set if none were found
727+
* @param element the annotated element (never {@code null})
728+
* @param annotationType the annotation type to find (never {@code null})
729+
* @return the set of all merged, synthesized {@code Annotations} found,
730+
* or an empty set if none were found
731731
* @since 4.3
732732
* @see #findMergedAnnotation(AnnotatedElement, Class)
733733
* @see #getAllMergedAnnotations(AnnotatedElement, Class)
@@ -756,10 +756,10 @@ public static <A extends Annotation> Set<A> findAllMergedAnnotations(AnnotatedEl
756756
* single annotation and within annotation hierarchies.
757757
* <p>This method follows <em>find semantics</em> as described in the
758758
* {@linkplain AnnotatedElementUtils class-level javadoc}.
759-
* @param element the annotated element; never {@code null}
760-
* @param annotationType the annotation type to find; never {@code null}
761-
* @return the set of all merged repeatable {@code Annotations} found, or an empty
762-
* set if none were found
759+
* @param element the annotated element (never {@code null})
760+
* @param annotationType the annotation type to find (never {@code null})
761+
* @return the set of all merged repeatable {@code Annotations} found,
762+
* or an empty set if none were found
763763
* @since 4.3
764764
* @see #findMergedAnnotation(AnnotatedElement, Class)
765765
* @see #findAllMergedAnnotations(AnnotatedElement, Class)
@@ -784,13 +784,13 @@ public static <A extends Annotation> Set<A> findMergedRepeatableAnnotations(Anno
784784
* single annotation and within annotation hierarchies.
785785
* <p>This method follows <em>find semantics</em> as described in the
786786
* {@linkplain AnnotatedElementUtils class-level javadoc}.
787-
* @param element the annotated element; never {@code null}
788-
* @param annotationType the annotation type to find; never {@code null}
787+
* @param element the annotated element (never {@code null})
788+
* @param annotationType the annotation type to find (never {@code null})
789789
* @param containerType the type of the container that holds the annotations;
790790
* may be {@code null} if the container type should be looked up via
791791
* {@link java.lang.annotation.Repeatable}
792-
* @return the set of all merged repeatable {@code Annotations} found, or an empty
793-
* set if none were found
792+
* @return the set of all merged repeatable {@code Annotations} found,
793+
* or an empty set if none were found
794794
* @since 4.3
795795
* @see #findMergedAnnotation(AnnotatedElement, Class)
796796
* @see #findAllMergedAnnotations(AnnotatedElement, Class)
@@ -947,9 +947,10 @@ private static <T> T searchWithGetSemanticsInAnnotations(AnnotatedElement elemen
947947

948948
// Search in annotations
949949
for (Annotation annotation : annotations) {
950-
if (!AnnotationUtils.isInJavaLangAnnotationPackage(annotation)) {
951-
if (annotation.annotationType() == annotationType ||
952-
annotation.annotationType().getName().equals(annotationName) ||
950+
Class<? extends Annotation> currentAnnotationType = annotation.annotationType();
951+
if (!AnnotationUtils.isInJavaLangAnnotationPackage(currentAnnotationType)) {
952+
if (currentAnnotationType == annotationType ||
953+
currentAnnotationType.getName().equals(annotationName) ||
953954
processor.alwaysProcesses()) {
954955
T result = processor.process(element, annotation, metaDepth);
955956
if (result != null) {
@@ -962,7 +963,7 @@ private static <T> T searchWithGetSemanticsInAnnotations(AnnotatedElement elemen
962963
}
963964
}
964965
// Repeatable annotations in container?
965-
else if (annotation.annotationType() == containerType) {
966+
else if (currentAnnotationType == containerType) {
966967
for (Annotation contained : getRawAnnotationsFromContainer(element, annotation)) {
967968
T result = processor.process(element, contained, metaDepth);
968969
if (result != null) {
@@ -977,8 +978,9 @@ else if (annotation.annotationType() == containerType) {
977978

978979
// Recursively search in meta-annotations
979980
for (Annotation annotation : annotations) {
980-
if (!AnnotationUtils.isInJavaLangAnnotationPackage(annotation)) {
981-
T result = searchWithGetSemantics(annotation.annotationType(), annotationType,
981+
Class<? extends Annotation> currentAnnotationType = annotation.annotationType();
982+
if (!AnnotationUtils.isInJavaLangAnnotationPackage(currentAnnotationType)) {
983+
T result = searchWithGetSemantics(currentAnnotationType, annotationType,
982984
annotationName, containerType, processor, visited, metaDepth + 1);
983985
if (result != null) {
984986
processor.postProcess(element, annotation, result);
@@ -1051,7 +1053,7 @@ private static <T> T searchWithFindSemantics(AnnotatedElement element, Class<? e
10511053
* have already been <em>visited</em>.
10521054
* <p>The {@code metaDepth} parameter is explained in the
10531055
* {@link Processor#process process()} method of the {@link Processor} API.
1054-
* @param element the annotated element; never {@code null}
1056+
* @param element the annotated element (never {@code null})
10551057
* @param annotationType the annotation type to find
10561058
* @param annotationName the fully qualified class name of the annotation
10571059
* type to find (as an alternative to {@code annotationType})
@@ -1077,11 +1079,11 @@ private static <T> T searchWithFindSemantics(AnnotatedElement element, Class<? e
10771079

10781080
// Search in local annotations
10791081
for (Annotation annotation : annotations) {
1080-
if (!AnnotationUtils.isInJavaLangAnnotationPackage(annotation)) {
1081-
if (annotation.annotationType() == annotationType
1082-
|| annotation.annotationType().getName().equals(annotationName)
1083-
|| processor.alwaysProcesses()) {
1084-
1082+
Class<? extends Annotation> currentAnnotationType = annotation.annotationType();
1083+
if (!AnnotationUtils.isInJavaLangAnnotationPackage(currentAnnotationType)) {
1084+
if (currentAnnotationType == annotationType ||
1085+
currentAnnotationType.getName().equals(annotationName) ||
1086+
processor.alwaysProcesses()) {
10851087
T result = processor.process(element, annotation, metaDepth);
10861088
if (result != null) {
10871089
if (processor.aggregates() && metaDepth == 0) {
@@ -1093,7 +1095,7 @@ private static <T> T searchWithFindSemantics(AnnotatedElement element, Class<? e
10931095
}
10941096
}
10951097
// Repeatable annotations in container?
1096-
else if (annotation.annotationType() == containerType) {
1098+
else if (currentAnnotationType == containerType) {
10971099
for (Annotation contained : getRawAnnotationsFromContainer(element, annotation)) {
10981100
T result = processor.process(element, contained, metaDepth);
10991101
if (result != null) {
@@ -1108,11 +1110,12 @@ else if (annotation.annotationType() == containerType) {
11081110

11091111
// Search in meta annotations on local annotations
11101112
for (Annotation annotation : annotations) {
1111-
if (!AnnotationUtils.isInJavaLangAnnotationPackage(annotation)) {
1112-
T result = searchWithFindSemantics(annotation.annotationType(), annotationType, annotationName,
1113+
Class<? extends Annotation> currentAnnotationType = annotation.annotationType();
1114+
if (!AnnotationUtils.isInJavaLangAnnotationPackage(currentAnnotationType)) {
1115+
T result = searchWithFindSemantics(currentAnnotationType, annotationType, annotationName,
11131116
containerType, processor, visited, metaDepth + 1);
11141117
if (result != null) {
1115-
processor.postProcess(annotation.annotationType(), annotation, result);
1118+
processor.postProcess(currentAnnotationType, annotation, result);
11161119
if (processor.aggregates() && metaDepth == 0) {
11171120
aggregatedResults.add(result);
11181121
}
@@ -1252,7 +1255,7 @@ private static <A extends Annotation> A[] getRawAnnotationsFromContainer(Annotat
12521255
* Resolve the container type for the supplied repeatable {@code annotationType}.
12531256
* <p>Delegates to {@link AnnotationUtils#resolveContainerAnnotationType(Class)}.
12541257
* @param annotationType the annotation type to resolve the container for
1255-
* @return the container type; never {@code null}
1258+
* @return the container type (never {@code null})
12561259
* @throws IllegalArgumentException if the container type cannot be resolved
12571260
* @since 4.3
12581261
*/
@@ -1403,8 +1406,8 @@ private interface Processor<T> {
14031406
* responsible for asking this processor if it {@link #aggregates} results
14041407
* and then adding the post-processed results to the list returned by this
14051408
* method.
1406-
* @return the list of results aggregated by this processor; never
1407-
* {@code null} unless {@link #aggregates} returns {@code false}
1409+
* @return the list of results aggregated by this processor
1410+
* (never {@code null} unless {@link #aggregates} returns {@code false})
14081411
* @see #aggregates
14091412
* @since 4.3
14101413
*/

spring-core/src/main/java/org/springframework/core/annotation/AnnotationUtils.java

Lines changed: 30 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,7 @@
6464
* <h3>Terminology</h3>
6565
* The terms <em>directly present</em>, <em>indirectly present</em>, and
6666
* <em>present</em> have the same meanings as defined in the class-level
67-
* Javadoc for {@link AnnotatedElement} (in Java 8).
67+
* javadoc for {@link AnnotatedElement} (in Java 8).
6868
*
6969
* <p>An annotation is <em>meta-present</em> on an element if the annotation
7070
* is declared as a meta-annotation on some other annotation which is
@@ -492,9 +492,10 @@ private static <A extends Annotation> A findAnnotation(
492492
if (annotation != null) {
493493
return annotation;
494494
}
495-
for (Annotation ann : annotatedElement.getDeclaredAnnotations()) {
496-
if (!isInJavaLangAnnotationPackage(ann) && visited.add(ann)) {
497-
annotation = findAnnotation((AnnotatedElement) ann.annotationType(), annotationType, visited);
495+
for (Annotation declaredAnn : annotatedElement.getDeclaredAnnotations()) {
496+
Class<? extends Annotation> declaredType = declaredAnn.annotationType();
497+
if (!isInJavaLangAnnotationPackage(declaredType) && visited.add(declaredAnn)) {
498+
annotation = findAnnotation((AnnotatedElement) declaredType, annotationType, visited);
498499
if (annotation != null) {
499500
return annotation;
500501
}
@@ -679,9 +680,10 @@ private static <A extends Annotation> A findAnnotation(Class<?> clazz, Class<A>
679680
if (annotation != null) {
680681
return annotation;
681682
}
682-
for (Annotation ann : clazz.getDeclaredAnnotations()) {
683-
if (!isInJavaLangAnnotationPackage(ann) && visited.add(ann)) {
684-
annotation = findAnnotation(ann.annotationType(), annotationType, visited);
683+
for (Annotation declaredAnn : clazz.getDeclaredAnnotations()) {
684+
Class<? extends Annotation> declaredType = declaredAnn.annotationType();
685+
if (!isInJavaLangAnnotationPackage(declaredType) && visited.add(declaredAnn)) {
686+
annotation = findAnnotation(declaredType, annotationType, visited);
685687
if (annotation != null) {
686688
return annotation;
687689
}
@@ -816,7 +818,7 @@ public static boolean isAnnotationDeclaredLocally(Class<? extends Annotation> an
816818
* <p>If the supplied {@code clazz} is an interface, only the interface
817819
* itself will be checked. In accordance with standard meta-annotation
818820
* semantics in Java, the inheritance hierarchy for interfaces will not
819-
* be traversed. See the {@linkplain java.lang.annotation.Inherited Javadoc}
821+
* be traversed. See the {@linkplain java.lang.annotation.Inherited javadoc}
820822
* for the {@code @Inherited} meta-annotation for further details regarding
821823
* annotation inheritance.
822824
* @param annotationType the annotation type to look for
@@ -868,13 +870,24 @@ public static boolean isAnnotationMetaPresent(Class<? extends Annotation> annota
868870
* @return {@code true} if the annotation is in the {@code java.lang.annotation} package
869871
*/
870872
public static boolean isInJavaLangAnnotationPackage(Annotation annotation) {
871-
return (annotation != null && isInJavaLangAnnotationPackage(annotation.annotationType().getName()));
873+
return (annotation != null && isInJavaLangAnnotationPackage(annotation.annotationType()));
872874
}
873875

874876
/**
875877
* Determine if the {@link Annotation} with the supplied name is defined
876878
* in the core JDK {@code java.lang.annotation} package.
877-
* @param annotationType the name of the annotation type to check (never {@code null} or empty)
879+
* @param annotationType the annotation type to check
880+
* @return {@code true} if the annotation is in the {@code java.lang.annotation} package
881+
* @since 4.3.8
882+
*/
883+
static boolean isInJavaLangAnnotationPackage(Class<? extends Annotation> annotationType) {
884+
return (annotationType != null && isInJavaLangAnnotationPackage(annotationType.getName()));
885+
}
886+
887+
/**
888+
* Determine if the {@link Annotation} with the supplied name is defined
889+
* in the core JDK {@code java.lang.annotation} package.
890+
* @param annotationType the name of the annotation type to check
878891
* @return {@code true} if the annotation is in the {@code java.lang.annotation} package
879892
* @since 4.2
880893
*/
@@ -1519,8 +1532,8 @@ static Annotation[] synthesizeAnnotationArray(Annotation[] annotations, Object a
15191532
* {@linkplain #synthesizeAnnotation(Map, Class, AnnotatedElement)
15201533
* synthesized} versions of the maps from the input array.
15211534
* @param maps the array of maps of annotation attributes to synthesize
1522-
* @param annotationType the type of annotations to synthesize; never
1523-
* {@code null}
1535+
* @param annotationType the type of annotations to synthesize
1536+
* (never {@code null})
15241537
* @return a new array of synthesized annotations, or {@code null} if
15251538
* the supplied array is {@code null}
15261539
* @throws AnnotationConfigurationException if invalid configuration of
@@ -1668,8 +1681,8 @@ static List<String> getAttributeAliasNames(Method attribute) {
16681681
/**
16691682
* Get the name of the overridden attribute configured via
16701683
* {@link AliasFor @AliasFor} for the supplied annotation {@code attribute}.
1671-
* @param attribute the attribute from which to retrieve the override;
1672-
* never {@code null}
1684+
* @param attribute the attribute from which to retrieve the override
1685+
* (never {@code null})
16731686
* @param metaAnnotationType the type of meta-annotation in which the
16741687
* overridden attribute is allowed to be declared
16751688
* @return the name of the overridden attribute, or {@code null} if not
@@ -1696,8 +1709,8 @@ static String getAttributeOverrideName(Method attribute, Class<? extends Annotat
16961709
* match Java's requirements for annotation <em>attributes</em>.
16971710
* <p>All methods in the returned list will be
16981711
* {@linkplain ReflectionUtils#makeAccessible(Method) made accessible}.
1699-
* @param annotationType the type in which to search for attribute methods;
1700-
* never {@code null}
1712+
* @param annotationType the type in which to search for attribute methods
1713+
* (never {@code null})
17011714
* @return all annotation attribute methods in the specified annotation
17021715
* type (never {@code null}, though potentially <em>empty</em>)
17031716
* @since 4.2
@@ -1906,7 +1919,7 @@ private void process(AnnotatedElement element) {
19061919
else if (ObjectUtils.nullSafeEquals(this.containerAnnotationType, currentAnnotationType)) {
19071920
this.result.addAll(getValue(element, ann));
19081921
}
1909-
else if (!isInJavaLangAnnotationPackage(ann)) {
1922+
else if (!isInJavaLangAnnotationPackage(currentAnnotationType)) {
19101923
process(currentAnnotationType);
19111924
}
19121925
}

spring-core/src/main/java/org/springframework/core/type/classreading/AnnotationAttributesReadingVisitor.java

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -92,17 +92,18 @@ public void visitEnd() {
9292
}
9393

9494
private void recursivelyCollectMetaAnnotations(Set<Annotation> visited, Annotation annotation) {
95-
if (!AnnotationUtils.isInJavaLangAnnotationPackage(annotation) && visited.add(annotation)) {
95+
Class<? extends Annotation> annotationType = annotation.annotationType();
96+
String annotationName = annotationType.getName();
97+
if (!AnnotationUtils.isInJavaLangAnnotationPackage(annotationName) && visited.add(annotation)) {
9698
try {
9799
// Only do attribute scanning for public annotations; we'd run into
98100
// IllegalAccessExceptions otherwise, and we don't want to mess with
99101
// accessibility in a SecurityManager environment.
100-
if (Modifier.isPublic(annotation.annotationType().getModifiers())) {
101-
String annotationName = annotation.annotationType().getName();
102+
if (Modifier.isPublic(annotationType.getModifiers())) {
102103
this.attributesMap.add(annotationName,
103104
AnnotationUtils.getAnnotationAttributes(annotation, false, true));
104105
}
105-
for (Annotation metaMetaAnnotation : annotation.annotationType().getAnnotations()) {
106+
for (Annotation metaMetaAnnotation : annotationType.getAnnotations()) {
106107
recursivelyCollectMetaAnnotations(visited, metaMetaAnnotation);
107108
}
108109
}

0 commit comments

Comments
 (0)