2323import java .lang .reflect .Modifier ;
2424import java .util .Arrays ;
2525import java .util .Map ;
26+ import java .util .function .Predicate ;
2627
2728import org .springframework .core .BridgeMethodResolver ;
2829import org .springframework .core .Ordered ;
2930import org .springframework .core .ResolvableType ;
31+ import org .springframework .core .annotation .MergedAnnotations .Search ;
3032import org .springframework .core .annotation .MergedAnnotations .SearchStrategy ;
3133import org .springframework .lang .Nullable ;
3234import org .springframework .util .ConcurrentReferenceHashMap ;
@@ -67,23 +69,27 @@ private AnnotationsScanner() {
6769 * processor
6870 * @param source the source element to scan
6971 * @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
7075 * @param processor the processor that receives the annotations
7176 * @return the result of {@link AnnotationsProcessor#finish(Object)}
7277 */
7378 @ Nullable
7479 static <C , R > R scan (C context , AnnotatedElement source , SearchStrategy searchStrategy ,
75- AnnotationsProcessor <C , R > processor ) {
80+ Predicate < Class <?>> searchEnclosingClass , AnnotationsProcessor <C , R > processor ) {
7681
77- R result = process (context , source , searchStrategy , processor );
82+ R result = process (context , source , searchStrategy , searchEnclosingClass , processor );
7883 return processor .finish (result );
7984 }
8085
8186 @ Nullable
8287 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 ) {
8490
8591 if (source instanceof Class <?> clazz ) {
86- return processClass (context , clazz , searchStrategy , processor );
92+ return processClass (context , clazz , searchStrategy , searchEnclosingClass , processor );
8793 }
8894 if (source instanceof Method method ) {
8995 return processMethod (context , method , searchStrategy , processor );
@@ -93,15 +99,15 @@ private static <C, R> R process(C context, AnnotatedElement source,
9399
94100 @ Nullable
95101 @ 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 ) {
98104
99105 return switch (searchStrategy ) {
100106 case DIRECT -> processElement (context , source , processor );
101107 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 );
105111 };
106112 }
107113
@@ -110,7 +116,7 @@ private static <C, R> R processClassInheritedAnnotations(C context, Class<?> sou
110116 SearchStrategy searchStrategy , AnnotationsProcessor <C , R > processor ) {
111117
112118 try {
113- if (isWithoutHierarchy (source , searchStrategy )) {
119+ if (isWithoutHierarchy (source , searchStrategy , Search . never )) {
114120 return processElement (context , source , processor );
115121 }
116122 Annotation [] relevant = null ;
@@ -161,15 +167,17 @@ private static <C, R> R processClassInheritedAnnotations(C context, Class<?> sou
161167
162168 @ Nullable
163169 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 ) {
165172
166173 return processClassHierarchy (context , new int [] {0 }, source , processor ,
167- includeInterfaces , includeEnclosing );
174+ includeInterfaces , searchEnclosingClass );
168175 }
169176
170177 @ Nullable
171178 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 ) {
173181
174182 try {
175183 R result = processor .doWithAggregate (context , aggregateIndex [0 ]);
@@ -188,7 +196,7 @@ private static <C, R> R processClassHierarchy(C context, int[] aggregateIndex, C
188196 if (includeInterfaces ) {
189197 for (Class <?> interfaceType : source .getInterfaces ()) {
190198 R interfacesResult = processClassHierarchy (context , aggregateIndex ,
191- interfaceType , processor , true , includeEnclosing );
199+ interfaceType , processor , true , searchEnclosingClass );
192200 if (interfacesResult != null ) {
193201 return interfacesResult ;
194202 }
@@ -197,12 +205,12 @@ private static <C, R> R processClassHierarchy(C context, int[] aggregateIndex, C
197205 Class <?> superclass = source .getSuperclass ();
198206 if (superclass != Object .class && superclass != null ) {
199207 R superclassResult = processClassHierarchy (context , aggregateIndex ,
200- superclass , processor , includeInterfaces , includeEnclosing );
208+ superclass , processor , includeInterfaces , searchEnclosingClass );
201209 if (superclassResult != null ) {
202210 return superclassResult ;
203211 }
204212 }
205- if (includeEnclosing ) {
213+ if (searchEnclosingClass . test ( source ) ) {
206214 // Since merely attempting to load the enclosing class may result in
207215 // automatic loading of sibling nested classes that in turn results
208216 // 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
212220 Class <?> enclosingClass = source .getEnclosingClass ();
213221 if (enclosingClass != null ) {
214222 R enclosingResult = processClassHierarchy (context , aggregateIndex ,
215- enclosingClass , processor , includeInterfaces , true );
223+ enclosingClass , processor , includeInterfaces , searchEnclosingClass );
216224 if (enclosingResult != null ) {
217225 return enclosingResult ;
218226 }
@@ -472,11 +480,13 @@ private static boolean isIgnorable(Class<?> annotationType) {
472480 return AnnotationFilter .PLAIN .matches (annotationType );
473481 }
474482
475- static boolean isKnownEmpty (AnnotatedElement source , SearchStrategy searchStrategy ) {
483+ static boolean isKnownEmpty (AnnotatedElement source , SearchStrategy searchStrategy ,
484+ Predicate <Class <?>> searchEnclosingClass ) {
485+
476486 if (hasPlainJavaAnnotationsOnly (source )) {
477487 return true ;
478488 }
479- if (searchStrategy == SearchStrategy .DIRECT || isWithoutHierarchy (source , searchStrategy )) {
489+ if (searchStrategy == SearchStrategy .DIRECT || isWithoutHierarchy (source , searchStrategy , searchEnclosingClass )) {
480490 if (source instanceof Method method && method .isBridge ()) {
481491 return false ;
482492 }
@@ -502,19 +512,21 @@ static boolean hasPlainJavaAnnotationsOnly(Class<?> type) {
502512 }
503513
504514 @ 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+
506518 if (source == Object .class ) {
507519 return true ;
508520 }
509521 if (source instanceof Class <?> sourceClass ) {
510522 boolean noSuperTypes = (sourceClass .getSuperclass () == Object .class &&
511523 sourceClass .getInterfaces ().length == 0 );
512- return (searchStrategy == SearchStrategy . TYPE_HIERARCHY_AND_ENCLOSING_CLASSES ? noSuperTypes &&
524+ return (searchEnclosingClass . test ( sourceClass ) ? noSuperTypes &&
513525 sourceClass .getEnclosingClass () == null : noSuperTypes );
514526 }
515527 if (source instanceof Method sourceMethod ) {
516528 return (Modifier .isPrivate (sourceMethod .getModifiers ()) ||
517- isWithoutHierarchy (sourceMethod .getDeclaringClass (), searchStrategy ));
529+ isWithoutHierarchy (sourceMethod .getDeclaringClass (), searchStrategy , searchEnclosingClass ));
518530 }
519531 return true ;
520532 }
0 commit comments