33
33
import org .junit .Ignore ;
34
34
import org .junit .Rule ;
35
35
import org .junit .Test ;
36
+ import org .junit .internal .ArrayComparisonFailure ;
36
37
import org .junit .rules .ExpectedException ;
37
38
39
+ import org .springframework .core .annotation .AnnotationUtilsTests .WebController ;
40
+ import org .springframework .core .annotation .AnnotationUtilsTests .WebMapping ;
38
41
import org .springframework .stereotype .Component ;
39
42
import org .springframework .util .Assert ;
40
43
import org .springframework .util .MultiValueMap ;
44
47
import static org .hamcrest .Matchers .*;
45
48
import static org .junit .Assert .*;
46
49
import static org .springframework .core .annotation .AnnotatedElementUtils .*;
50
+ import static org .springframework .core .annotation .AnnotationUtilsTests .*;
47
51
48
52
/**
49
53
* Unit tests for {@link AnnotatedElementUtils}.
@@ -379,11 +383,21 @@ public void getMergedAnnotationWithTransitiveImplicitAliases() {
379
383
assertGetMergedAnnotation (TransitiveImplicitAliasesContextConfigClass .class , "test.groovy" );
380
384
}
381
385
386
+ @ Test
387
+ public void getMergedAnnotationWithTransitiveImplicitAliasesWithSingleElementOverridingAnArrayViaAliasFor () {
388
+ assertGetMergedAnnotation (SingleLocationTransitiveImplicitAliasesContextConfigClass .class , "test.groovy" );
389
+ }
390
+
382
391
@ Test
383
392
public void getMergedAnnotationWithTransitiveImplicitAliasesWithSkippedLevel () {
384
393
assertGetMergedAnnotation (TransitiveImplicitAliasesWithSkippedLevelContextConfigClass .class , "test.xml" );
385
394
}
386
395
396
+ @ Test
397
+ public void getMergedAnnotationWithTransitiveImplicitAliasesWithSkippedLevelWithSingleElementOverridingAnArrayViaAliasFor () {
398
+ assertGetMergedAnnotation (SingleLocationTransitiveImplicitAliasesWithSkippedLevelContextConfigClass .class , "test.xml" );
399
+ }
400
+
387
401
private void assertGetMergedAnnotation (Class <?> element , String ... expected ) {
388
402
String name = ContextConfig .class .getName ();
389
403
ContextConfig contextConfig = getMergedAnnotation (element , ContextConfig .class );
@@ -560,6 +574,53 @@ public void findAndSynthesizeAnnotationAttributesOnClassWithAttributeAliasesInTa
560
574
assertEquals ("TX qualifier via synthesized annotation." , qualifier , annotation .qualifier ());
561
575
}
562
576
577
+ @ Test
578
+ public void findMergedAnnotationAttributesOnClassWithAttributeAliasInComposedAnnotationAndNestedAnnotationsInTargetAnnotation () {
579
+ AnnotationAttributes attributes = assertComponentScanAttributes (TestComponentScanClass .class ,
580
+ "com.example.app.test" );
581
+
582
+ Filter [] excludeFilters = attributes .getAnnotationArray ("excludeFilters" , Filter .class );
583
+ assertNotNull (excludeFilters );
584
+
585
+ List <String > patterns = stream (excludeFilters ).map (Filter ::pattern ).collect (toList ());
586
+ assertEquals (asList ("*Test" , "*Tests" ), patterns );
587
+ }
588
+
589
+ /**
590
+ * This test ensures that {@link AnnotationUtils#postProcessAnnotationAttributes}
591
+ * uses {@code ObjectUtils.nullSafeEquals()} to check for equality between annotation
592
+ * attributes since attributes may be arrays.
593
+ */
594
+ @ Test
595
+ public void findMergedAnnotationAttributesOnClassWithBothAttributesOfAnAliasPairDeclared () {
596
+ assertComponentScanAttributes (ComponentScanWithBasePackagesAndValueAliasClass .class , "com.example.app.test" );
597
+ }
598
+
599
+ @ Test
600
+ public void findMergedAnnotationAttributesWithSingleElementOverridingAnArrayViaConvention () {
601
+ assertComponentScanAttributes (ConventionBasedSinglePackageComponentScanClass .class , "com.example.app.test" );
602
+ }
603
+
604
+ @ Test
605
+ public void findMergedAnnotationAttributesWithSingleElementOverridingAnArrayViaAliasFor () {
606
+ assertComponentScanAttributes (AliasForBasedSinglePackageComponentScanClass .class , "com.example.app.test" );
607
+ }
608
+
609
+ private AnnotationAttributes assertComponentScanAttributes (Class <?> element , String ... expected ) {
610
+ AnnotationAttributes attributes = findMergedAnnotationAttributes (element , ComponentScan .class );
611
+
612
+ assertNotNull ("Should find @ComponentScan on " + element , attributes );
613
+ assertArrayEquals ("value: " , expected , attributes .getStringArray ("value" ));
614
+ assertArrayEquals ("basePackages: " , expected , attributes .getStringArray ("basePackages" ));
615
+
616
+ return attributes ;
617
+ }
618
+
619
+ private AnnotationAttributes findMergedAnnotationAttributes (AnnotatedElement element , Class <? extends Annotation > annotationType ) {
620
+ Assert .notNull (annotationType , "annotationType must not be null" );
621
+ return AnnotatedElementUtils .findMergedAnnotationAttributes (element , annotationType .getName (), false , false );
622
+ }
623
+
563
624
@ Test
564
625
public void findMergedAnnotationWithAttributeAliasesInTargetAnnotation () {
565
626
Class <?> element = AliasedTransactionalComponentClass .class ;
@@ -593,38 +654,6 @@ public void findMergedAnnotationForMultipleMetaAnnotationsWithClashingAttributeN
593
654
assertArrayEquals ("value" , propFiles , testPropSource .value ());
594
655
}
595
656
596
- @ Test
597
- public void findMergedAnnotationAttributesOnClassWithAttributeAliasInComposedAnnotationAndNestedAnnotationsInTargetAnnotation () {
598
- String [] expected = asArray ("com.example.app.test" );
599
- Class <?> element = TestComponentScanClass .class ;
600
- AnnotationAttributes attributes = findMergedAnnotationAttributes (element , ComponentScan .class );
601
-
602
- assertNotNull ("Should find @ComponentScan on " + element , attributes );
603
- assertArrayEquals ("basePackages for " + element , expected , attributes .getStringArray ("basePackages" ));
604
-
605
- Filter [] excludeFilters = attributes .getAnnotationArray ("excludeFilters" , Filter .class );
606
- assertNotNull (excludeFilters );
607
-
608
- List <String > patterns = stream (excludeFilters ).map (Filter ::pattern ).collect (toList ());
609
- assertEquals (asList ("*Test" , "*Tests" ), patterns );
610
- }
611
-
612
- /**
613
- * This test ensures that {@link AnnotationUtils#postProcessAnnotationAttributes}
614
- * uses {@code ObjectUtils.nullSafeEquals()} to check for equality between annotation
615
- * attributes since attributes may be arrays.
616
- */
617
- @ Test
618
- public void findMergedAnnotationAttributesOnClassWithBothAttributesOfAnAliasPairDeclared () {
619
- String [] expected = asArray ("com.example.app.test" );
620
- Class <?> element = ComponentScanWithBasePackagesAndValueAliasClass .class ;
621
- AnnotationAttributes attributes = findMergedAnnotationAttributes (element , ComponentScan .class );
622
-
623
- assertNotNull ("Should find @ComponentScan on " + element , attributes );
624
- assertArrayEquals ("value: " , expected , attributes .getStringArray ("value" ));
625
- assertArrayEquals ("basePackages: " , expected , attributes .getStringArray ("basePackages" ));
626
- }
627
-
628
657
@ Test
629
658
public void findMergedAnnotationWithLocalAliasesThatConflictWithAttributesInMetaAnnotationByConvention () {
630
659
final String [] EMPTY = new String [0 ];
@@ -638,6 +667,24 @@ public void findMergedAnnotationWithLocalAliasesThatConflictWithAttributesInMeta
638
667
assertArrayEquals ("classes for " + element , new Class <?>[] {Number .class }, contextConfig .classes ());
639
668
}
640
669
670
+ @ Test
671
+ public void findMergedAnnotationWithSingleElementOverridingAnArrayViaConvention () throws Exception {
672
+ assertWebMapping (WebController .class .getMethod ("postMappedWithPathAttribute" ));
673
+ }
674
+
675
+ @ Test
676
+ public void findMergedAnnotationWithSingleElementOverridingAnArrayViaAliasFor () throws Exception {
677
+ assertWebMapping (WebController .class .getMethod ("getMappedWithValueAttribute" ));
678
+ assertWebMapping (WebController .class .getMethod ("getMappedWithPathAttribute" ));
679
+ }
680
+
681
+ private void assertWebMapping (AnnotatedElement element ) throws ArrayComparisonFailure {
682
+ WebMapping webMapping = findMergedAnnotation (element , WebMapping .class );
683
+ assertNotNull (webMapping );
684
+ assertArrayEquals ("value attribute: " , asArray ("/test" ), webMapping .value ());
685
+ assertArrayEquals ("path attribute: " , asArray ("/test" ), webMapping .path ());
686
+ }
687
+
641
688
@ Test
642
689
public void javaLangAnnotationTypeViaFindMergedAnnotation () throws Exception {
643
690
Constructor <?> deprecatedCtor = Date .class .getConstructor (String .class );
@@ -651,28 +698,10 @@ public void javaxAnnotationTypeViaFindMergedAnnotation() throws Exception {
651
698
assertEquals (SpringAppConfigClass .class .getAnnotation (Resource .class ), findMergedAnnotation (SpringAppConfigClass .class , Resource .class ));
652
699
}
653
700
654
-
655
701
private Set <String > names (Class <?>... classes ) {
656
702
return stream (classes ).map (Class ::getName ).collect (toSet ());
657
703
}
658
704
659
- @ SafeVarargs
660
- // The following "varargs" suppression is necessary for javac from OpenJDK
661
- // (1.8.0_60-b27); however, Eclipse warns that it's unnecessary. See the following
662
- // Eclipse issues for details.
663
- //
664
- // https://bugs.eclipse.org/bugs/show_bug.cgi?id=344783
665
- // https://bugs.eclipse.org/bugs/show_bug.cgi?id=349669#c10
666
- // @SuppressWarnings("varargs")
667
- private static <T > T [] asArray (T ... arr ) {
668
- return arr ;
669
- }
670
-
671
- private static AnnotationAttributes findMergedAnnotationAttributes (AnnotatedElement element , Class <? extends Annotation > annotationType ) {
672
- Assert .notNull (annotationType , "annotationType must not be null" );
673
- return AnnotatedElementUtils .findMergedAnnotationAttributes (element , annotationType .getName (), false , false );
674
- }
675
-
676
705
677
706
// -------------------------------------------------------------------------
678
707
@@ -881,6 +910,17 @@ static class MetaCycleAnnotatedClass {
881
910
String [] groovy () default {};
882
911
}
883
912
913
+ @ ImplicitAliasesContextConfig
914
+ @ Retention (RetentionPolicy .RUNTIME )
915
+ @interface SingleLocationTransitiveImplicitAliasesContextConfig {
916
+
917
+ @ AliasFor (annotation = ImplicitAliasesContextConfig .class , attribute = "xmlFiles" )
918
+ String xml () default "" ;
919
+
920
+ @ AliasFor (annotation = ImplicitAliasesContextConfig .class , attribute = "groovyScripts" )
921
+ String groovy () default "" ;
922
+ }
923
+
884
924
@ ImplicitAliasesContextConfig
885
925
@ Retention (RetentionPolicy .RUNTIME )
886
926
@interface TransitiveImplicitAliasesWithSkippedLevelContextConfig {
@@ -892,6 +932,17 @@ static class MetaCycleAnnotatedClass {
892
932
String [] groovy () default {};
893
933
}
894
934
935
+ @ ImplicitAliasesContextConfig
936
+ @ Retention (RetentionPolicy .RUNTIME )
937
+ @interface SingleLocationTransitiveImplicitAliasesWithSkippedLevelContextConfig {
938
+
939
+ @ AliasFor (annotation = ContextConfig .class , attribute = "locations" )
940
+ String xml () default "" ;
941
+
942
+ @ AliasFor (annotation = ImplicitAliasesContextConfig .class , attribute = "groovyScripts" )
943
+ String groovy () default "" ;
944
+ }
945
+
895
946
/**
896
947
* Invalid because the configuration declares a value for 'value' and
897
948
* requires a value for the aliased 'locations'. So we likely end up with
@@ -958,6 +1009,21 @@ static class MetaCycleAnnotatedClass {
958
1009
@ Retention (RetentionPolicy .RUNTIME )
959
1010
@interface TestComponentScan {
960
1011
1012
+ @ AliasFor (attribute = "basePackages" , annotation = ComponentScan .class )
1013
+ String [] packages ();
1014
+ }
1015
+
1016
+ @ ComponentScan
1017
+ @ Retention (RetentionPolicy .RUNTIME )
1018
+ @interface ConventionBasedSinglePackageComponentScan {
1019
+
1020
+ String basePackages ();
1021
+ }
1022
+
1023
+ @ ComponentScan
1024
+ @ Retention (RetentionPolicy .RUNTIME )
1025
+ @interface AliasForBasedSinglePackageComponentScan {
1026
+
961
1027
@ AliasFor (attribute = "basePackages" , annotation = ComponentScan .class )
962
1028
String pkg ();
963
1029
}
@@ -1132,10 +1198,18 @@ static class ImplicitAliasesContextConfigClass3 {
1132
1198
static class TransitiveImplicitAliasesContextConfigClass {
1133
1199
}
1134
1200
1201
+ @ SingleLocationTransitiveImplicitAliasesContextConfig (groovy = "test.groovy" )
1202
+ static class SingleLocationTransitiveImplicitAliasesContextConfigClass {
1203
+ }
1204
+
1135
1205
@ TransitiveImplicitAliasesWithSkippedLevelContextConfig (xml = "test.xml" )
1136
1206
static class TransitiveImplicitAliasesWithSkippedLevelContextConfigClass {
1137
1207
}
1138
1208
1209
+ @ SingleLocationTransitiveImplicitAliasesWithSkippedLevelContextConfig (xml = "test.xml" )
1210
+ static class SingleLocationTransitiveImplicitAliasesWithSkippedLevelContextConfigClass {
1211
+ }
1212
+
1139
1213
@ ComposedImplicitAliasesContextConfig
1140
1214
static class ComposedImplicitAliasesContextConfigClass {
1141
1215
}
@@ -1152,10 +1226,18 @@ static class AliasedComposedContextConfigAndTestPropSourceClass {
1152
1226
static class ComponentScanWithBasePackagesAndValueAliasClass {
1153
1227
}
1154
1228
1155
- @ TestComponentScan (pkg = "com.example.app.test" )
1229
+ @ TestComponentScan (packages = "com.example.app.test" )
1156
1230
static class TestComponentScanClass {
1157
1231
}
1158
1232
1233
+ @ ConventionBasedSinglePackageComponentScan (basePackages = "com.example.app.test" )
1234
+ static class ConventionBasedSinglePackageComponentScanClass {
1235
+ }
1236
+
1237
+ @ AliasForBasedSinglePackageComponentScan (pkg = "com.example.app.test" )
1238
+ static class AliasForBasedSinglePackageComponentScanClass {
1239
+ }
1240
+
1159
1241
@ SpringAppConfig (Number .class )
1160
1242
static class SpringAppConfigClass {
1161
1243
}
0 commit comments