23
23
import java .lang .reflect .Modifier ;
24
24
import java .util .Arrays ;
25
25
import java .util .Map ;
26
+ import java .util .function .Predicate ;
26
27
27
28
import org .springframework .core .BridgeMethodResolver ;
28
29
import org .springframework .core .Ordered ;
29
30
import org .springframework .core .ResolvableType ;
31
+ import org .springframework .core .annotation .MergedAnnotations .Search ;
30
32
import org .springframework .core .annotation .MergedAnnotations .SearchStrategy ;
31
33
import org .springframework .lang .Nullable ;
32
34
import org .springframework .util .ConcurrentReferenceHashMap ;
@@ -67,23 +69,27 @@ private AnnotationsScanner() {
67
69
* processor
68
70
* @param source the source element to scan
69
71
* @param searchStrategy the search strategy to use
72
+ * @param searchEnclosingClass a predicate which evaluates to {@code true}
73
+ * if a search should be performed on the enclosing class of the class
74
+ * supplied to the predicate
70
75
* @param processor the processor that receives the annotations
71
76
* @return the result of {@link AnnotationsProcessor#finish(Object)}
72
77
*/
73
78
@ Nullable
74
79
static <C , R > R scan (C context , AnnotatedElement source , SearchStrategy searchStrategy ,
75
- AnnotationsProcessor <C , R > processor ) {
80
+ Predicate < Class <?>> searchEnclosingClass , AnnotationsProcessor <C , R > processor ) {
76
81
77
- R result = process (context , source , searchStrategy , processor );
82
+ R result = process (context , source , searchStrategy , searchEnclosingClass , processor );
78
83
return processor .finish (result );
79
84
}
80
85
81
86
@ Nullable
82
87
private static <C , R > R process (C context , AnnotatedElement source ,
83
- SearchStrategy searchStrategy , AnnotationsProcessor <C , R > processor ) {
88
+ SearchStrategy searchStrategy , Predicate <Class <?>> searchEnclosingClass ,
89
+ AnnotationsProcessor <C , R > processor ) {
84
90
85
91
if (source instanceof Class <?> clazz ) {
86
- return processClass (context , clazz , searchStrategy , processor );
92
+ return processClass (context , clazz , searchStrategy , searchEnclosingClass , processor );
87
93
}
88
94
if (source instanceof Method method ) {
89
95
return processMethod (context , method , searchStrategy , processor );
@@ -93,15 +99,15 @@ private static <C, R> R process(C context, AnnotatedElement source,
93
99
94
100
@ Nullable
95
101
@ SuppressWarnings ("deprecation" )
96
- private static <C , R > R processClass (C context , Class <?> source ,
97
- SearchStrategy searchStrategy , AnnotationsProcessor <C , R > processor ) {
102
+ private static <C , R > R processClass (C context , Class <?> source , SearchStrategy searchStrategy ,
103
+ Predicate < Class <?>> searchEnclosingClass , AnnotationsProcessor <C , R > processor ) {
98
104
99
105
return switch (searchStrategy ) {
100
106
case DIRECT -> processElement (context , source , processor );
101
107
case INHERITED_ANNOTATIONS -> processClassInheritedAnnotations (context , source , searchStrategy , processor );
102
- case SUPERCLASS -> processClassHierarchy (context , source , processor , false , false );
103
- case TYPE_HIERARCHY -> processClassHierarchy (context , source , processor , true , false );
104
- case TYPE_HIERARCHY_AND_ENCLOSING_CLASSES -> processClassHierarchy (context , source , processor , true , true );
108
+ case SUPERCLASS -> processClassHierarchy (context , source , processor , false , Search . never );
109
+ case TYPE_HIERARCHY -> processClassHierarchy (context , source , processor , true , searchEnclosingClass );
110
+ case TYPE_HIERARCHY_AND_ENCLOSING_CLASSES -> processClassHierarchy (context , source , processor , true , Search . always );
105
111
};
106
112
}
107
113
@@ -110,7 +116,7 @@ private static <C, R> R processClassInheritedAnnotations(C context, Class<?> sou
110
116
SearchStrategy searchStrategy , AnnotationsProcessor <C , R > processor ) {
111
117
112
118
try {
113
- if (isWithoutHierarchy (source , searchStrategy )) {
119
+ if (isWithoutHierarchy (source , searchStrategy , Search . never )) {
114
120
return processElement (context , source , processor );
115
121
}
116
122
Annotation [] relevant = null ;
@@ -161,15 +167,17 @@ private static <C, R> R processClassInheritedAnnotations(C context, Class<?> sou
161
167
162
168
@ Nullable
163
169
private static <C , R > R processClassHierarchy (C context , Class <?> source ,
164
- AnnotationsProcessor <C , R > processor , boolean includeInterfaces , boolean includeEnclosing ) {
170
+ AnnotationsProcessor <C , R > processor , boolean includeInterfaces ,
171
+ Predicate <Class <?>> searchEnclosingClass ) {
165
172
166
173
return processClassHierarchy (context , new int [] {0 }, source , processor ,
167
- includeInterfaces , includeEnclosing );
174
+ includeInterfaces , searchEnclosingClass );
168
175
}
169
176
170
177
@ Nullable
171
178
private static <C , R > R processClassHierarchy (C context , int [] aggregateIndex , Class <?> source ,
172
- AnnotationsProcessor <C , R > processor , boolean includeInterfaces , boolean includeEnclosing ) {
179
+ AnnotationsProcessor <C , R > processor , boolean includeInterfaces ,
180
+ Predicate <Class <?>> searchEnclosingClass ) {
173
181
174
182
try {
175
183
R result = processor .doWithAggregate (context , aggregateIndex [0 ]);
@@ -188,7 +196,7 @@ private static <C, R> R processClassHierarchy(C context, int[] aggregateIndex, C
188
196
if (includeInterfaces ) {
189
197
for (Class <?> interfaceType : source .getInterfaces ()) {
190
198
R interfacesResult = processClassHierarchy (context , aggregateIndex ,
191
- interfaceType , processor , true , includeEnclosing );
199
+ interfaceType , processor , true , searchEnclosingClass );
192
200
if (interfacesResult != null ) {
193
201
return interfacesResult ;
194
202
}
@@ -197,12 +205,12 @@ private static <C, R> R processClassHierarchy(C context, int[] aggregateIndex, C
197
205
Class <?> superclass = source .getSuperclass ();
198
206
if (superclass != Object .class && superclass != null ) {
199
207
R superclassResult = processClassHierarchy (context , aggregateIndex ,
200
- superclass , processor , includeInterfaces , includeEnclosing );
208
+ superclass , processor , includeInterfaces , searchEnclosingClass );
201
209
if (superclassResult != null ) {
202
210
return superclassResult ;
203
211
}
204
212
}
205
- if (includeEnclosing ) {
213
+ if (searchEnclosingClass . test ( source ) ) {
206
214
// Since merely attempting to load the enclosing class may result in
207
215
// automatic loading of sibling nested classes that in turn results
208
216
// in an exception such as NoClassDefFoundError, we wrap the following
@@ -212,7 +220,7 @@ private static <C, R> R processClassHierarchy(C context, int[] aggregateIndex, C
212
220
Class <?> enclosingClass = source .getEnclosingClass ();
213
221
if (enclosingClass != null ) {
214
222
R enclosingResult = processClassHierarchy (context , aggregateIndex ,
215
- enclosingClass , processor , includeInterfaces , true );
223
+ enclosingClass , processor , includeInterfaces , searchEnclosingClass );
216
224
if (enclosingResult != null ) {
217
225
return enclosingResult ;
218
226
}
@@ -472,11 +480,13 @@ private static boolean isIgnorable(Class<?> annotationType) {
472
480
return AnnotationFilter .PLAIN .matches (annotationType );
473
481
}
474
482
475
- static boolean isKnownEmpty (AnnotatedElement source , SearchStrategy searchStrategy ) {
483
+ static boolean isKnownEmpty (AnnotatedElement source , SearchStrategy searchStrategy ,
484
+ Predicate <Class <?>> searchEnclosingClass ) {
485
+
476
486
if (hasPlainJavaAnnotationsOnly (source )) {
477
487
return true ;
478
488
}
479
- if (searchStrategy == SearchStrategy .DIRECT || isWithoutHierarchy (source , searchStrategy )) {
489
+ if (searchStrategy == SearchStrategy .DIRECT || isWithoutHierarchy (source , searchStrategy , searchEnclosingClass )) {
480
490
if (source instanceof Method method && method .isBridge ()) {
481
491
return false ;
482
492
}
@@ -502,19 +512,21 @@ static boolean hasPlainJavaAnnotationsOnly(Class<?> type) {
502
512
}
503
513
504
514
@ SuppressWarnings ("deprecation" )
505
- private static boolean isWithoutHierarchy (AnnotatedElement source , SearchStrategy searchStrategy ) {
515
+ private static boolean isWithoutHierarchy (AnnotatedElement source , SearchStrategy searchStrategy ,
516
+ Predicate <Class <?>> searchEnclosingClass ) {
517
+
506
518
if (source == Object .class ) {
507
519
return true ;
508
520
}
509
521
if (source instanceof Class <?> sourceClass ) {
510
522
boolean noSuperTypes = (sourceClass .getSuperclass () == Object .class &&
511
523
sourceClass .getInterfaces ().length == 0 );
512
- return (searchStrategy == SearchStrategy . TYPE_HIERARCHY_AND_ENCLOSING_CLASSES ? noSuperTypes &&
524
+ return (searchEnclosingClass . test ( sourceClass ) ? noSuperTypes &&
513
525
sourceClass .getEnclosingClass () == null : noSuperTypes );
514
526
}
515
527
if (source instanceof Method sourceMethod ) {
516
528
return (Modifier .isPrivate (sourceMethod .getModifiers ()) ||
517
- isWithoutHierarchy (sourceMethod .getDeclaringClass (), searchStrategy ));
529
+ isWithoutHierarchy (sourceMethod .getDeclaringClass (), searchStrategy , searchEnclosingClass ));
518
530
}
519
531
return true ;
520
532
}
0 commit comments