diff --git a/spring-core/src/main/java/org/springframework/core/annotation/AnnotationUtils.java b/spring-core/src/main/java/org/springframework/core/annotation/AnnotationUtils.java index 0a5f7246c30..b2631831b9b 100644 --- a/spring-core/src/main/java/org/springframework/core/annotation/AnnotationUtils.java +++ b/spring-core/src/main/java/org/springframework/core/annotation/AnnotationUtils.java @@ -924,11 +924,10 @@ public abstract class AnnotationUtils { return mappedAnnotations; } else { - Annotation[] synthesizedAnnotations = new Annotation[annotations.length]; for (int i = 0; i < annotations.length; i++) { - synthesizedAnnotations[i] = synthesizeAnnotation(annotations[i], annotatedElement); + annotations[i] = synthesizeAnnotation(annotations[i], annotatedElement); } - return synthesizedAnnotations; + return annotations; } } diff --git a/spring-core/src/test/java/org/springframework/core/annotation/AnnotatedElementUtilsTests.java b/spring-core/src/test/java/org/springframework/core/annotation/AnnotatedElementUtilsTests.java index 305de6537cf..d885830a170 100644 --- a/spring-core/src/test/java/org/springframework/core/annotation/AnnotatedElementUtilsTests.java +++ b/spring-core/src/test/java/org/springframework/core/annotation/AnnotatedElementUtilsTests.java @@ -22,8 +22,8 @@ import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; import java.lang.reflect.Method; +import java.util.List; import java.util.Set; -import java.util.stream.Collectors; import org.junit.Rule; import org.junit.Test; @@ -32,9 +32,9 @@ import org.junit.rules.ExpectedException; import org.springframework.stereotype.Component; import org.springframework.util.MultiValueMap; -import static org.hamcrest.Matchers.*; - import static java.util.Arrays.*; +import static java.util.stream.Collectors.*; +import static org.hamcrest.Matchers.*; import static org.junit.Assert.*; import static org.springframework.core.annotation.AnnotatedElementUtils.*; @@ -460,8 +460,23 @@ public class AnnotatedElementUtilsTests { attributes.getString("qualifier")); } + @Test + public void findAnnotationAttributesOnClassWithAttributeAliasInComposedAnnotationAndNestedAnnotationsInTargetAnnotation() { + Class element = TestComponentScanClass.class; + AnnotationAttributes attributes = findAnnotationAttributes(element, ComponentScan.class); + assertNotNull("Should find @ComponentScan on " + element, attributes); + assertArrayEquals("basePackages for " + element, new String[] { "com.example.app.test" }, + attributes.getStringArray("basePackages")); + + Filter[] excludeFilters = attributes.getAnnotationArray("excludeFilters", Filter.class); + assertNotNull(excludeFilters); + + List patterns = stream(excludeFilters).map(Filter::pattern).collect(toList()); + assertEquals(asList("*Test", "*Tests"), patterns); + } + private Set names(Class... classes) { - return stream(classes).map(clazz -> clazz.getName()).collect(Collectors.toSet()); + return stream(classes).map(Class::getName).collect(toSet()); } @@ -627,6 +642,32 @@ public class AnnotatedElementUtilsTests { String[] xmlConfigFiles(); } + /** + * Mock of {@code org.springframework.context.annotation.ComponentScan} + */ + @Retention(RetentionPolicy.RUNTIME) + @interface ComponentScan { + + String[] basePackages() default {}; + + Filter[] excludeFilters() default {}; + } + + @Retention(RetentionPolicy.RUNTIME) + @Target({}) + @interface Filter { + + String pattern(); + } + + @ComponentScan(excludeFilters = { @Filter(pattern = "*Test"), @Filter(pattern = "*Tests") }) + @Retention(RetentionPolicy.RUNTIME) + @interface TestComponentScan { + + @AliasFor(attribute = "basePackages", annotation = ComponentScan.class) + String[] packages(); + } + // ------------------------------------------------------------------------- static class NonAnnotatedClass { @@ -776,4 +817,9 @@ public class AnnotatedElementUtilsTests { @InvalidAliasedComposedContextConfig(xmlConfigFiles = "test.xml") static class InvalidAliasedComposedContextConfigClass { } + + @TestComponentScan(packages = "com.example.app.test") + static class TestComponentScanClass { + } + } diff --git a/spring-core/src/test/java/org/springframework/core/annotation/AnnotationUtilsTests.java b/spring-core/src/test/java/org/springframework/core/annotation/AnnotationUtilsTests.java index a549f7c76e5..01f8f62a86e 100644 --- a/spring-core/src/test/java/org/springframework/core/annotation/AnnotationUtilsTests.java +++ b/spring-core/src/test/java/org/springframework/core/annotation/AnnotationUtilsTests.java @@ -21,6 +21,7 @@ import java.lang.annotation.Inherited; import java.lang.annotation.Repeatable; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; import java.lang.reflect.Method; import java.util.Arrays; import java.util.List; @@ -35,6 +36,7 @@ import org.springframework.core.annotation.subpackage.NonPublicAnnotatedClass; import org.springframework.stereotype.Component; import org.springframework.util.ClassUtils; +import static java.util.Arrays.*; import static java.util.stream.Collectors.*; import static org.hamcrest.Matchers.*; import static org.junit.Assert.*; @@ -393,6 +395,22 @@ public class AnnotationUtilsTests { assertEquals(Component.class, attributes.annotationType()); } + @Test + public void getAnnotationAttributesWithNestedAnnotations() { + ComponentScan componentScan = ComponentScanClass.class.getAnnotation(ComponentScan.class); + assertNotNull(componentScan); + + AnnotationAttributes attributes = getAnnotationAttributes(ComponentScanClass.class, componentScan); + assertNotNull(attributes); + assertEquals(ComponentScan.class, attributes.annotationType()); + + Filter[] filters = attributes.getAnnotationArray("excludeFilters", Filter.class); + assertNotNull(filters); + + List patterns = stream(filters).map(Filter::pattern).collect(toList()); + assertEquals(asList("*Foo", "*Bar"), patterns); + } + @Test public void getAnnotationAttributesWithAttributeAliases() throws Exception { Method method = WebController.class.getMethod("handleMappedWithValueAttribute"); @@ -1222,4 +1240,22 @@ public class AnnotationUtilsTests { String xmlConfigFile(); } + @Retention(RetentionPolicy.RUNTIME) + @Target({}) + @interface Filter { + String pattern(); + } + + /** + * Mock of {@code org.springframework.context.annotation.ComponentScan} + */ + @Retention(RetentionPolicy.RUNTIME) + @interface ComponentScan { + Filter[] excludeFilters() default {}; + } + + @ComponentScan(excludeFilters = { @Filter(pattern = "*Foo"), @Filter(pattern = "*Bar") }) + static class ComponentScanClass { + } + }