From 7cedffc707a327dfa56e0ef4808fe892ea38c470 Mon Sep 17 00:00:00 2001 From: Sam Brannen Date: Fri, 29 Nov 2019 00:07:44 +0100 Subject: [PATCH] Support @Inherited again in reflection-based AnnotationMetadata Spring Framework 5.2 introduced a regression in reflection-based AnnotationMetadata. Specifically, as of 5.2, StandardAnnotationMetadata no longer found @Inherited annotations from superclasses. This commit fixes this regression by switching to the INHERITED_ANNOTATIONS SearchStrategy when creating the MergedAnnotations used within StandardAnnotationMetadata, Note, however, that the discrepancy between StandardAnnotationMetadata and SimpleAnnotationMetadata (i.e., reflection-based vs. ASM-based) regarding @Inherited support still remains as it was prior to Spring Framework 5.2. Closes gh-24077 --- .../core/type/StandardAnnotationMetadata.java | 2 +- .../core/type/AnnotationMetadataTests.java | 51 +++++++------------ 2 files changed, 20 insertions(+), 33 deletions(-) diff --git a/spring-core/src/main/java/org/springframework/core/type/StandardAnnotationMetadata.java b/spring-core/src/main/java/org/springframework/core/type/StandardAnnotationMetadata.java index c0f680d260e8..b7dbbdab517f 100644 --- a/spring-core/src/main/java/org/springframework/core/type/StandardAnnotationMetadata.java +++ b/spring-core/src/main/java/org/springframework/core/type/StandardAnnotationMetadata.java @@ -85,7 +85,7 @@ public StandardAnnotationMetadata(Class introspectedClass) { public StandardAnnotationMetadata(Class introspectedClass, boolean nestedAnnotationsAsMap) { super(introspectedClass); this.mergedAnnotations = MergedAnnotations.from(introspectedClass, - SearchStrategy.DIRECT, RepeatableContainers.none(), + SearchStrategy.INHERITED_ANNOTATIONS, RepeatableContainers.none(), AnnotationFilter.NONE); this.nestedAnnotationsAsMap = nestedAnnotationsAsMap; } diff --git a/spring-core/src/test/java/org/springframework/core/type/AnnotationMetadataTests.java b/spring-core/src/test/java/org/springframework/core/type/AnnotationMetadataTests.java index 5442c9b8d6ac..f1f9ddbed5be 100644 --- a/spring-core/src/test/java/org/springframework/core/type/AnnotationMetadataTests.java +++ b/spring-core/src/test/java/org/springframework/core/type/AnnotationMetadataTests.java @@ -42,7 +42,7 @@ /** * Unit tests demonstrating that the reflection-based {@link StandardAnnotationMetadata} - * and ASM-based {@code AnnotationMetadataReadingVisitor} produce identical output. + * and ASM-based {@code SimpleAnnotationMetadata} produce almost identical output. * * @author Juergen Hoeller * @author Chris Beams @@ -51,9 +51,6 @@ */ class AnnotationMetadataTests { - private static final boolean reproduceGh24077 = false; - - @Test void standardAnnotationMetadata() { AnnotationMetadata metadata = AnnotationMetadata.introspect(AnnotatedComponent.class); @@ -73,7 +70,7 @@ void asmAnnotationMetadata() throws Exception { @Test void standardAnnotationMetadataForSubclass() { AnnotationMetadata metadata = AnnotationMetadata.introspect(AnnotatedComponentSubClass.class); - doTestSubClassAnnotationInfo(metadata); + doTestSubClassAnnotationInfo(metadata, false); } @Test @@ -81,10 +78,10 @@ void asmAnnotationMetadataForSubclass() throws Exception { MetadataReaderFactory metadataReaderFactory = new SimpleMetadataReaderFactory(); MetadataReader metadataReader = metadataReaderFactory.getMetadataReader(AnnotatedComponentSubClass.class.getName()); AnnotationMetadata metadata = metadataReader.getAnnotationMetadata(); - doTestSubClassAnnotationInfo(metadata); + doTestSubClassAnnotationInfo(metadata, true); } - private void doTestSubClassAnnotationInfo(AnnotationMetadata metadata) { + private void doTestSubClassAnnotationInfo(AnnotationMetadata metadata, boolean asm) { assertThat(metadata.getClassName()).isEqualTo(AnnotatedComponentSubClass.class.getName()); assertThat(metadata.isInterface()).isFalse(); assertThat(metadata.isAnnotation()).isFalse(); @@ -97,16 +94,16 @@ private void doTestSubClassAnnotationInfo(AnnotationMetadata metadata) { assertThat(metadata.isAnnotated(Scope.class.getName())).isFalse(); assertThat(metadata.isAnnotated(SpecialAttr.class.getName())).isFalse(); - if (reproduceGh24077) { - assertThat(metadata.isAnnotated(NamedComposedAnnotation.class.getName())).isTrue(); - assertThat(metadata.hasAnnotation(NamedComposedAnnotation.class.getName())).isTrue(); - assertThat(metadata.getAnnotationTypes()).containsExactly(NamedComposedAnnotation.class.getName()); - } - else { + if (asm) { assertThat(metadata.isAnnotated(NamedComposedAnnotation.class.getName())).isFalse(); assertThat(metadata.hasAnnotation(NamedComposedAnnotation.class.getName())).isFalse(); assertThat(metadata.getAnnotationTypes()).isEmpty(); } + else { + assertThat(metadata.isAnnotated(NamedComposedAnnotation.class.getName())).isTrue(); + assertThat(metadata.hasAnnotation(NamedComposedAnnotation.class.getName())).isTrue(); + assertThat(metadata.getAnnotationTypes()).containsExactly(NamedComposedAnnotation.class.getName()); + } assertThat(metadata.hasAnnotation(Component.class.getName())).isFalse(); assertThat(metadata.hasAnnotation(Scope.class.getName())).isFalse(); @@ -252,7 +249,7 @@ void composedAnnotationWithMetaAnnotationsWithIdenticalAttributeNamesUsingAnnota @Test void inheritedAnnotationWithMetaAnnotationsWithIdenticalAttributeNamesUsingStandardAnnotationMetadata() { AnnotationMetadata metadata = AnnotationMetadata.introspect(NamedComposedAnnotationExtended.class); - assertThat(metadata.hasAnnotation(NamedComposedAnnotation.class.getName())).isFalse(); + assertThat(metadata.hasAnnotation(NamedComposedAnnotation.class.getName())).isTrue(); } @Test @@ -294,29 +291,18 @@ private void doTestAnnotationInfo(AnnotationMetadata metadata) { assertThat(metadata.isAnnotated(Component.class.getName())).isTrue(); - if (reproduceGh24077) { - assertThat(metadata.isAnnotated(NamedComposedAnnotation.class.getName())).isTrue(); - } + assertThat(metadata.isAnnotated(NamedComposedAnnotation.class.getName())).isTrue(); assertThat(metadata.hasAnnotation(Component.class.getName())).isTrue(); assertThat(metadata.hasAnnotation(Scope.class.getName())).isTrue(); assertThat(metadata.hasAnnotation(SpecialAttr.class.getName())).isTrue(); - if (reproduceGh24077) { - assertThat(metadata.hasAnnotation(NamedComposedAnnotation.class.getName())).isTrue(); - assertThat(metadata.getAnnotationTypes()).containsExactlyInAnyOrder( - Component.class.getName(), Scope.class.getName(), - SpecialAttr.class.getName(), DirectAnnotation.class.getName(), - MetaMetaAnnotation.class.getName(), EnumSubclasses.class.getName(), - NamedComposedAnnotation.class.getName()); - } - else { - assertThat(metadata.hasAnnotation(NamedComposedAnnotation.class.getName())).isFalse(); - assertThat(metadata.getAnnotationTypes()).containsExactlyInAnyOrder( - Component.class.getName(), Scope.class.getName(), - SpecialAttr.class.getName(), DirectAnnotation.class.getName(), - MetaMetaAnnotation.class.getName(), EnumSubclasses.class.getName()); - } + assertThat(metadata.hasAnnotation(NamedComposedAnnotation.class.getName())).isTrue(); + assertThat(metadata.getAnnotationTypes()).containsExactlyInAnyOrder( + Component.class.getName(), Scope.class.getName(), + SpecialAttr.class.getName(), DirectAnnotation.class.getName(), + MetaMetaAnnotation.class.getName(), EnumSubclasses.class.getName(), + NamedComposedAnnotation.class.getName()); AnnotationAttributes compAttrs = (AnnotationAttributes) metadata.getAnnotationAttributes(Component.class.getName()); assertThat(compAttrs).hasSize(1); @@ -513,6 +499,7 @@ public enum SubclassEnum { @DirectAnnotation(value = "direct", additional = "", additionalArray = {}) @MetaMetaAnnotation @EnumSubclasses({SubclassEnum.FOO, SubclassEnum.BAR}) + @NamedComposedAnnotation private static class AnnotatedComponent implements Serializable { @TestAutowired