2525import java .util .ArrayList ;
2626import java .util .Arrays ;
2727import java .util .List ;
28+ import java .util .Objects ;
2829import java .util .stream .Stream ;
2930
3031import org .junit .jupiter .api .Test ;
3132
3233import org .springframework .core .annotation .MergedAnnotations .SearchStrategy ;
3334import org .springframework .lang .Nullable ;
34- import org .springframework .util .ClassUtils ;
3535import org .springframework .util .ReflectionUtils ;
3636
3737import static org .assertj .core .api .Assertions .assertThat ;
4040 * Tests for {@link AnnotationsScanner}.
4141 *
4242 * @author Phillip Webb
43+ * @author Sam Brannen
4344 */
4445class AnnotationsScannerTests {
4546
@@ -115,7 +116,7 @@ void inheritedAnnotationsStrategyOnClassWhenHasInterfaceDoesNotIncludeInterfaces
115116 void inheritedAnnotationsStrategyOnClassHierarchyScansInCorrectOrder () {
116117 Class <?> source = WithHierarchy .class ;
117118 assertThat (scan (source , SearchStrategy .INHERITED_ANNOTATIONS )).containsExactly (
118- "0:TestAnnotation1" , "1:TestInheritedAnnotation2" );
119+ "0:TestAnnotation1" , "1:TestInheritedAnnotation2" , "2:TestInheritedAnnotation3" );
119120 }
120121
121122 @ Test
@@ -124,7 +125,52 @@ void inheritedAnnotationsStrategyOnClassWhenHasAnnotationOnBothClassesIncudesOnl
124125 assertThat (Arrays .stream (source .getAnnotations ()).map (
125126 Annotation ::annotationType ).map (Class ::getName )).containsExactly (
126127 TestInheritedAnnotation2 .class .getName ());
127- assertThat (scan (source , SearchStrategy .INHERITED_ANNOTATIONS )).containsOnly ("0:TestInheritedAnnotation2" );
128+ assertThat (scan (source , SearchStrategy .INHERITED_ANNOTATIONS )).containsExactly ("0:TestInheritedAnnotation2" );
129+ }
130+
131+ @ Test
132+ void inheritedAnnotationsStrategyOnClassWithAllClassesFilteredOut () {
133+ List <String > annotationsFound = new ArrayList <>();
134+ String scanResult = AnnotationsScanner .scan (this , WithSingleSuperclass .class ,
135+ SearchStrategy .INHERITED_ANNOTATIONS ,
136+ (context , aggregateIndex , source , annotations ) -> {
137+ trackIndexedAnnotations (aggregateIndex , annotations , annotationsFound );
138+ return null ; // continue searching
139+ },
140+ (context , clazz ) -> true // filter out all classes
141+ );
142+ assertThat (annotationsFound ).isEmpty ();
143+ assertThat (scanResult ).isNull ();
144+ }
145+
146+ @ Test
147+ void inheritedAnnotationsStrategyOnClassWithSourceClassFilteredOut () {
148+ List <String > annotationsFound = new ArrayList <>();
149+ String scanResult = AnnotationsScanner .scan (this , WithSingleSuperclass .class ,
150+ SearchStrategy .INHERITED_ANNOTATIONS ,
151+ (context , aggregateIndex , source , annotations ) -> {
152+ trackIndexedAnnotations (aggregateIndex , annotations , annotationsFound );
153+ return null ; // continue searching
154+ },
155+ (context , clazz ) -> clazz == WithSingleSuperclass .class
156+ );
157+ assertThat (annotationsFound ).containsExactly (/* "0:TestAnnotation1", */ "1:TestInheritedAnnotation2" );
158+ assertThat (scanResult ).isNull ();
159+ }
160+
161+ @ Test
162+ void inheritedAnnotationsStrategyInClassHierarchyWithSuperSuperclassFilteredOut () {
163+ List <String > annotationsFound = new ArrayList <>();
164+ String scanResult = AnnotationsScanner .scan (this , WithHierarchy .class ,
165+ SearchStrategy .INHERITED_ANNOTATIONS ,
166+ (context , aggregateIndex , source , annotations ) -> {
167+ trackIndexedAnnotations (aggregateIndex , annotations , annotationsFound );
168+ return null ; // continue searching
169+ },
170+ (context , clazz ) -> clazz == HierarchySuperSuperclass .class
171+ );
172+ assertThat (annotationsFound ).containsExactly ("0:TestAnnotation1" , "1:TestInheritedAnnotation2" );
173+ assertThat (scanResult ).isNull ();
128174 }
129175
130176 @ Test
@@ -163,7 +209,7 @@ void superclassStrategyOnClassHierarchyScansInCorrectOrder() {
163209 Class <?> source = WithHierarchy .class ;
164210 assertThat (scan (source , SearchStrategy .SUPERCLASS )).containsExactly (
165211 "0:TestAnnotation1" , "1:TestAnnotation2" , "1:TestInheritedAnnotation2" ,
166- "2:TestAnnotation3" );
212+ "2:TestAnnotation3" , "2:TestInheritedAnnotation3" );
167213 }
168214
169215 @ Test
@@ -205,7 +251,7 @@ void typeHierarchyStrategyOnClassHierarchyScansInCorrectOrder() {
205251 assertThat (scan (source , SearchStrategy .TYPE_HIERARCHY )).containsExactly (
206252 "0:TestAnnotation1" , "1:TestAnnotation5" , "1:TestInheritedAnnotation5" ,
207253 "2:TestAnnotation6" , "3:TestAnnotation2" , "3:TestInheritedAnnotation2" ,
208- "4:TestAnnotation3" , "5:TestAnnotation4" );
254+ "4:TestAnnotation3" , "4:TestInheritedAnnotation3" , " 5:TestAnnotation4" );
209255 }
210256
211257 @ Test
@@ -474,7 +520,7 @@ void scanWhenProcessorReturnsFromDoWithAnnotationsExitsEarly() {
474520 return "" ;
475521 });
476522 assertThat (result ).isEmpty ();
477- assertThat (indexes ).containsOnly (0 );
523+ assertThat (indexes ).containsExactly (0 );
478524 }
479525
480526 @ Test
@@ -499,42 +545,30 @@ public String finish(String result) {
499545 assertThat (result ).isEqualTo ("OK" );
500546 }
501547
502- @ Test
503- void scanWithFilteredAll () {
504- List <Integer > indexes = new ArrayList <>();
505- String result = AnnotationsScanner .scan (this , WithSingleSuperclass .class ,
506- SearchStrategy .INHERITED_ANNOTATIONS ,
507- (context , aggregateIndex , source , annotations ) -> {
508- indexes .add (aggregateIndex );
509- return "" ;
510- },
511- (context ,cls )->{
512- return true ;
513- }
514- );
515- assertThat (result ).isNull ();
516- }
517-
518548
519549 private Method methodFrom (Class <?> type ) {
520550 return ReflectionUtils .findMethod (type , "method" );
521551 }
522552
523553 private Stream <String > scan (AnnotatedElement element , SearchStrategy searchStrategy ) {
524- List <String > result = new ArrayList <>();
554+ List <String > results = new ArrayList <>();
525555 AnnotationsScanner .scan (this , element , searchStrategy ,
526556 (criteria , aggregateIndex , source , annotations ) -> {
527- for (Annotation annotation : annotations ) {
528- if (annotation != null ) {
529- String name = ClassUtils .getShortName (
530- annotation .annotationType ());
531- name = name .substring (name .lastIndexOf ("." ) + 1 );
532- result .add (aggregateIndex + ":" + name );
533- }
534- }
535- return null ;
557+ trackIndexedAnnotations (aggregateIndex , annotations , results );
558+ return null ; // continue searching
536559 });
537- return result .stream ();
560+ return results .stream ();
561+ }
562+
563+ private void trackIndexedAnnotations (int aggregateIndex , Annotation [] annotations , List <String > results ) {
564+ Arrays .stream (annotations )
565+ .filter (Objects ::nonNull )
566+ .map (annotation -> indexedName (aggregateIndex , annotation ))
567+ .forEach (results ::add );
568+ }
569+
570+ private String indexedName (int aggregateIndex , Annotation annotation ) {
571+ return aggregateIndex + ":" + annotation .annotationType ().getSimpleName ();
538572 }
539573
540574
@@ -686,6 +720,7 @@ public void method() {
686720 }
687721
688722 @ TestAnnotation3
723+ @ TestInheritedAnnotation3
689724 static class HierarchySuperSuperclass implements HierarchySuperSuperclassInterface {
690725
691726 @ Override
0 commit comments