Skip to content

Commit 8b05484

Browse files
committed
Minimize reflective interaction with annotation instances during retrieval
Issue: SPR-15387 (cherry picked from commit 3037277)
1 parent 7f3d0b3 commit 8b05484

File tree

4 files changed

+85
-70
lines changed

4 files changed

+85
-70
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
@@ -445,10 +445,10 @@ public static <A extends Annotation> A getMergedAnnotation(AnnotatedElement elem
445445
* single annotation and within annotation hierarchies.
446446
* <p>This method follows <em>get semantics</em> as described in the
447447
* {@linkplain AnnotatedElementUtils class-level javadoc}.
448-
* @param element the annotated element; never {@code null}
449-
* @param annotationType the annotation type to find; never {@code null}
450-
* @return the set of all merged, synthesized {@code Annotations} found, or an empty
451-
* set if none were found
448+
* @param element the annotated element (never {@code null})
449+
* @param annotationType the annotation type to find (never {@code null})
450+
* @return the set of all merged, synthesized {@code Annotations} found,
451+
* or an empty set if none were found
452452
* @since 4.3
453453
* @see #getMergedAnnotation(AnnotatedElement, Class)
454454
* @see #getAllAnnotationAttributes(AnnotatedElement, String)
@@ -478,10 +478,10 @@ public static <A extends Annotation> Set<A> getAllMergedAnnotations(AnnotatedEle
478478
* single annotation and within annotation hierarchies.
479479
* <p>This method follows <em>get semantics</em> as described in the
480480
* {@linkplain AnnotatedElementUtils class-level javadoc}.
481-
* @param element the annotated element; never {@code null}
482-
* @param annotationType the annotation type to find; never {@code null}
483-
* @return the set of all merged repeatable {@code Annotations} found, or an empty
484-
* set if none were found
481+
* @param element the annotated element (never {@code null})
482+
* @param annotationType the annotation type to find (never {@code null})
483+
* @return the set of all merged repeatable {@code Annotations} found,
484+
* or an empty set if none were found
485485
* @since 4.3
486486
* @see #getMergedAnnotation(AnnotatedElement, Class)
487487
* @see #getAllMergedAnnotations(AnnotatedElement, Class)
@@ -506,13 +506,13 @@ public static <A extends Annotation> Set<A> getMergedRepeatableAnnotations(Annot
506506
* single annotation and within annotation hierarchies.
507507
* <p>This method follows <em>get semantics</em> as described in the
508508
* {@linkplain AnnotatedElementUtils class-level javadoc}.
509-
* @param element the annotated element; never {@code null}
510-
* @param annotationType the annotation type to find; never {@code null}
509+
* @param element the annotated element (never {@code null})
510+
* @param annotationType the annotation type to find (never {@code null})
511511
* @param containerType the type of the container that holds the annotations;
512512
* may be {@code null} if the container type should be looked up via
513513
* {@link java.lang.annotation.Repeatable}
514-
* @return the set of all merged repeatable {@code Annotations} found, or an empty
515-
* set if none were found
514+
* @return the set of all merged repeatable {@code Annotations} found,
515+
* or an empty set if none were found
516516
* @since 4.3
517517
* @see #getMergedAnnotation(AnnotatedElement, Class)
518518
* @see #getAllMergedAnnotations(AnnotatedElement, Class)
@@ -771,10 +771,10 @@ public static <A extends Annotation> A findMergedAnnotation(AnnotatedElement ele
771771
* single annotation and within annotation hierarchies.
772772
* <p>This method follows <em>find semantics</em> as described in the
773773
* {@linkplain AnnotatedElementUtils class-level javadoc}.
774-
* @param element the annotated element; never {@code null}
775-
* @param annotationType the annotation type to find; never {@code null}
776-
* @return the set of all merged, synthesized {@code Annotations} found, or an empty
777-
* set if none were found
774+
* @param element the annotated element (never {@code null})
775+
* @param annotationType the annotation type to find (never {@code null})
776+
* @return the set of all merged, synthesized {@code Annotations} found,
777+
* or an empty set if none were found
778778
* @since 4.3
779779
* @see #findMergedAnnotation(AnnotatedElement, Class)
780780
* @see #getAllMergedAnnotations(AnnotatedElement, Class)
@@ -803,10 +803,10 @@ public static <A extends Annotation> Set<A> findAllMergedAnnotations(AnnotatedEl
803803
* single annotation and within annotation hierarchies.
804804
* <p>This method follows <em>find semantics</em> as described in the
805805
* {@linkplain AnnotatedElementUtils class-level javadoc}.
806-
* @param element the annotated element; never {@code null}
807-
* @param annotationType the annotation type to find; never {@code null}
808-
* @return the set of all merged repeatable {@code Annotations} found, or an empty
809-
* set if none were found
806+
* @param element the annotated element (never {@code null})
807+
* @param annotationType the annotation type to find (never {@code null})
808+
* @return the set of all merged repeatable {@code Annotations} found,
809+
* or an empty set if none were found
810810
* @since 4.3
811811
* @see #findMergedAnnotation(AnnotatedElement, Class)
812812
* @see #findAllMergedAnnotations(AnnotatedElement, Class)
@@ -831,13 +831,13 @@ public static <A extends Annotation> Set<A> findMergedRepeatableAnnotations(Anno
831831
* single annotation and within annotation hierarchies.
832832
* <p>This method follows <em>find semantics</em> as described in the
833833
* {@linkplain AnnotatedElementUtils class-level javadoc}.
834-
* @param element the annotated element; never {@code null}
835-
* @param annotationType the annotation type to find; never {@code null}
834+
* @param element the annotated element (never {@code null})
835+
* @param annotationType the annotation type to find (never {@code null})
836836
* @param containerType the type of the container that holds the annotations;
837837
* may be {@code null} if the container type should be looked up via
838838
* {@link java.lang.annotation.Repeatable}
839-
* @return the set of all merged repeatable {@code Annotations} found, or an empty
840-
* set if none were found
839+
* @return the set of all merged repeatable {@code Annotations} found,
840+
* or an empty set if none were found
841841
* @since 4.3
842842
* @see #findMergedAnnotation(AnnotatedElement, Class)
843843
* @see #findAllMergedAnnotations(AnnotatedElement, Class)
@@ -994,9 +994,10 @@ private static <T> T searchWithGetSemanticsInAnnotations(AnnotatedElement elemen
994994

995995
// Search in annotations
996996
for (Annotation annotation : annotations) {
997-
if (!AnnotationUtils.isInJavaLangAnnotationPackage(annotation)) {
998-
if (annotation.annotationType() == annotationType ||
999-
annotation.annotationType().getName().equals(annotationName) ||
997+
Class<? extends Annotation> currentAnnotationType = annotation.annotationType();
998+
if (!AnnotationUtils.isInJavaLangAnnotationPackage(currentAnnotationType)) {
999+
if (currentAnnotationType == annotationType ||
1000+
currentAnnotationType.getName().equals(annotationName) ||
10001001
processor.alwaysProcesses()) {
10011002
T result = processor.process(element, annotation, metaDepth);
10021003
if (result != null) {
@@ -1009,7 +1010,7 @@ private static <T> T searchWithGetSemanticsInAnnotations(AnnotatedElement elemen
10091010
}
10101011
}
10111012
// Repeatable annotations in container?
1012-
else if (annotation.annotationType() == containerType) {
1013+
else if (currentAnnotationType == containerType) {
10131014
for (Annotation contained : getRawAnnotationsFromContainer(element, annotation)) {
10141015
T result = processor.process(element, contained, metaDepth);
10151016
if (result != null) {
@@ -1024,8 +1025,9 @@ else if (annotation.annotationType() == containerType) {
10241025

10251026
// Recursively search in meta-annotations
10261027
for (Annotation annotation : annotations) {
1027-
if (!AnnotationUtils.isInJavaLangAnnotationPackage(annotation)) {
1028-
T result = searchWithGetSemantics(annotation.annotationType(), annotationType,
1028+
Class<? extends Annotation> currentAnnotationType = annotation.annotationType();
1029+
if (!AnnotationUtils.isInJavaLangAnnotationPackage(currentAnnotationType)) {
1030+
T result = searchWithGetSemantics(currentAnnotationType, annotationType,
10291031
annotationName, containerType, processor, visited, metaDepth + 1);
10301032
if (result != null) {
10311033
processor.postProcess(element, annotation, result);
@@ -1098,7 +1100,7 @@ private static <T> T searchWithFindSemantics(AnnotatedElement element, Class<? e
10981100
* have already been <em>visited</em>.
10991101
* <p>The {@code metaDepth} parameter is explained in the
11001102
* {@link Processor#process process()} method of the {@link Processor} API.
1101-
* @param element the annotated element; never {@code null}
1103+
* @param element the annotated element (never {@code null})
11021104
* @param annotationType the annotation type to find
11031105
* @param annotationName the fully qualified class name of the annotation
11041106
* type to find (as an alternative to {@code annotationType})
@@ -1124,11 +1126,11 @@ private static <T> T searchWithFindSemantics(AnnotatedElement element, Class<? e
11241126

11251127
// Search in local annotations
11261128
for (Annotation annotation : annotations) {
1127-
if (!AnnotationUtils.isInJavaLangAnnotationPackage(annotation)) {
1128-
if (annotation.annotationType() == annotationType
1129-
|| annotation.annotationType().getName().equals(annotationName)
1130-
|| processor.alwaysProcesses()) {
1131-
1129+
Class<? extends Annotation> currentAnnotationType = annotation.annotationType();
1130+
if (!AnnotationUtils.isInJavaLangAnnotationPackage(currentAnnotationType)) {
1131+
if (currentAnnotationType == annotationType ||
1132+
currentAnnotationType.getName().equals(annotationName) ||
1133+
processor.alwaysProcesses()) {
11321134
T result = processor.process(element, annotation, metaDepth);
11331135
if (result != null) {
11341136
if (processor.aggregates() && metaDepth == 0) {
@@ -1140,7 +1142,7 @@ private static <T> T searchWithFindSemantics(AnnotatedElement element, Class<? e
11401142
}
11411143
}
11421144
// Repeatable annotations in container?
1143-
else if (annotation.annotationType() == containerType) {
1145+
else if (currentAnnotationType == containerType) {
11441146
for (Annotation contained : getRawAnnotationsFromContainer(element, annotation)) {
11451147
T result = processor.process(element, contained, metaDepth);
11461148
if (result != null) {
@@ -1155,11 +1157,12 @@ else if (annotation.annotationType() == containerType) {
11551157

11561158
// Search in meta annotations on local annotations
11571159
for (Annotation annotation : annotations) {
1158-
if (!AnnotationUtils.isInJavaLangAnnotationPackage(annotation)) {
1159-
T result = searchWithFindSemantics(annotation.annotationType(), annotationType, annotationName,
1160+
Class<? extends Annotation> currentAnnotationType = annotation.annotationType();
1161+
if (!AnnotationUtils.isInJavaLangAnnotationPackage(currentAnnotationType)) {
1162+
T result = searchWithFindSemantics(currentAnnotationType, annotationType, annotationName,
11601163
containerType, processor, visited, metaDepth + 1);
11611164
if (result != null) {
1162-
processor.postProcess(annotation.annotationType(), annotation, result);
1165+
processor.postProcess(currentAnnotationType, annotation, result);
11631166
if (processor.aggregates() && metaDepth == 0) {
11641167
aggregatedResults.add(result);
11651168
}
@@ -1299,7 +1302,7 @@ private static <A extends Annotation> A[] getRawAnnotationsFromContainer(Annotat
12991302
* Resolve the container type for the supplied repeatable {@code annotationType}.
13001303
* <p>Delegates to {@link AnnotationUtils#resolveContainerAnnotationType(Class)}.
13011304
* @param annotationType the annotation type to resolve the container for
1302-
* @return the container type; never {@code null}
1305+
* @return the container type (never {@code null})
13031306
* @throws IllegalArgumentException if the container type cannot be resolved
13041307
* @since 4.3
13051308
*/
@@ -1450,8 +1453,8 @@ private interface Processor<T> {
14501453
* responsible for asking this processor if it {@link #aggregates} results
14511454
* and then adding the post-processed results to the list returned by this
14521455
* method.
1453-
* @return the list of results aggregated by this processor; never
1454-
* {@code null} unless {@link #aggregates} returns {@code false}
1456+
* @return the list of results aggregated by this processor
1457+
* (never {@code null} unless {@link #aggregates} returns {@code false})
14551458
* @see #aggregates
14561459
* @since 4.3
14571460
*/

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

Lines changed: 22 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2016 the original author or authors.
2+
* Copyright 2002-2017 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -63,7 +63,7 @@
6363
* <h3>Terminology</h3>
6464
* The terms <em>directly present</em>, <em>indirectly present</em>, and
6565
* <em>present</em> have the same meanings as defined in the class-level
66-
* Javadoc for {@link AnnotatedElement} (in Java 8).
66+
* javadoc for {@link AnnotatedElement} (in Java 8).
6767
*
6868
* <p>An annotation is <em>meta-present</em> on an element if the annotation
6969
* is declared as a meta-annotation on some other annotation which is
@@ -855,7 +855,7 @@ public static boolean isAnnotationDeclaredLocally(Class<? extends Annotation> an
855855
* <p>If the supplied {@code clazz} is an interface, only the interface
856856
* itself will be checked. In accordance with standard meta-annotation
857857
* semantics in Java, the inheritance hierarchy for interfaces will not
858-
* be traversed. See the {@linkplain java.lang.annotation.Inherited Javadoc}
858+
* be traversed. See the {@linkplain java.lang.annotation.Inherited javadoc}
859859
* for the {@code @Inherited} meta-annotation for further details regarding
860860
* annotation inheritance.
861861
* @param annotationType the annotation type to look for
@@ -907,13 +907,24 @@ public static boolean isAnnotationMetaPresent(Class<? extends Annotation> annota
907907
* @return {@code true} if the annotation is in the {@code java.lang.annotation} package
908908
*/
909909
public static boolean isInJavaLangAnnotationPackage(Annotation annotation) {
910-
return (annotation != null && isInJavaLangAnnotationPackage(annotation.annotationType().getName()));
910+
return (annotation != null && isInJavaLangAnnotationPackage(annotation.annotationType()));
911911
}
912912

913913
/**
914914
* Determine if the {@link Annotation} with the supplied name is defined
915915
* in the core JDK {@code java.lang.annotation} package.
916-
* @param annotationType the name of the annotation type to check (never {@code null} or empty)
916+
* @param annotationType the annotation type to check
917+
* @return {@code true} if the annotation is in the {@code java.lang.annotation} package
918+
* @since 4.3.8
919+
*/
920+
static boolean isInJavaLangAnnotationPackage(Class<? extends Annotation> annotationType) {
921+
return (annotationType != null && isInJavaLangAnnotationPackage(annotationType.getName()));
922+
}
923+
924+
/**
925+
* Determine if the {@link Annotation} with the supplied name is defined
926+
* in the core JDK {@code java.lang.annotation} package.
927+
* @param annotationType the name of the annotation type to check
917928
* @return {@code true} if the annotation is in the {@code java.lang.annotation} package
918929
* @since 4.2
919930
*/
@@ -1558,8 +1569,8 @@ static Annotation[] synthesizeAnnotationArray(Annotation[] annotations, Object a
15581569
* {@linkplain #synthesizeAnnotation(Map, Class, AnnotatedElement)
15591570
* synthesized} versions of the maps from the input array.
15601571
* @param maps the array of maps of annotation attributes to synthesize
1561-
* @param annotationType the type of annotations to synthesize; never
1562-
* {@code null}
1572+
* @param annotationType the type of annotations to synthesize
1573+
* (never {@code null})
15631574
* @return a new array of synthesized annotations, or {@code null} if
15641575
* the supplied array is {@code null}
15651576
* @throws AnnotationConfigurationException if invalid configuration of
@@ -1707,8 +1718,8 @@ static List<String> getAttributeAliasNames(Method attribute) {
17071718
/**
17081719
* Get the name of the overridden attribute configured via
17091720
* {@link AliasFor @AliasFor} for the supplied annotation {@code attribute}.
1710-
* @param attribute the attribute from which to retrieve the override;
1711-
* never {@code null}
1721+
* @param attribute the attribute from which to retrieve the override
1722+
* (never {@code null})
17121723
* @param metaAnnotationType the type of meta-annotation in which the
17131724
* overridden attribute is allowed to be declared
17141725
* @return the name of the overridden attribute, or {@code null} if not
@@ -1735,8 +1746,8 @@ static String getAttributeOverrideName(Method attribute, Class<? extends Annotat
17351746
* match Java's requirements for annotation <em>attributes</em>.
17361747
* <p>All methods in the returned list will be
17371748
* {@linkplain ReflectionUtils#makeAccessible(Method) made accessible}.
1738-
* @param annotationType the type in which to search for attribute methods;
1739-
* never {@code null}
1749+
* @param annotationType the type in which to search for attribute methods
1750+
* (never {@code null})
17401751
* @return all annotation attribute methods in the specified annotation
17411752
* type (never {@code null}, though potentially <em>empty</em>)
17421753
* @since 4.2

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)