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
This commit is contained in:
Sam Brannen 2019-11-29 00:07:44 +01:00
parent 85016aef30
commit 7cedffc707
2 changed files with 20 additions and 33 deletions

View File

@ -85,7 +85,7 @@ public class StandardAnnotationMetadata extends StandardClassMetadata implements
public StandardAnnotationMetadata(Class<?> introspectedClass, boolean nestedAnnotationsAsMap) { public StandardAnnotationMetadata(Class<?> introspectedClass, boolean nestedAnnotationsAsMap) {
super(introspectedClass); super(introspectedClass);
this.mergedAnnotations = MergedAnnotations.from(introspectedClass, this.mergedAnnotations = MergedAnnotations.from(introspectedClass,
SearchStrategy.DIRECT, RepeatableContainers.none(), SearchStrategy.INHERITED_ANNOTATIONS, RepeatableContainers.none(),
AnnotationFilter.NONE); AnnotationFilter.NONE);
this.nestedAnnotationsAsMap = nestedAnnotationsAsMap; this.nestedAnnotationsAsMap = nestedAnnotationsAsMap;
} }

View File

@ -42,7 +42,7 @@ import static org.assertj.core.api.Assertions.assertThat;
/** /**
* Unit tests demonstrating that the reflection-based {@link StandardAnnotationMetadata} * Unit tests demonstrating that the reflection-based {@link StandardAnnotationMetadata}
* and ASM-based {@code AnnotationMetadataReadingVisitor} produce identical output. * and ASM-based {@code SimpleAnnotationMetadata} produce <em>almost</em> identical output.
* *
* @author Juergen Hoeller * @author Juergen Hoeller
* @author Chris Beams * @author Chris Beams
@ -51,9 +51,6 @@ import static org.assertj.core.api.Assertions.assertThat;
*/ */
class AnnotationMetadataTests { class AnnotationMetadataTests {
private static final boolean reproduceGh24077 = false;
@Test @Test
void standardAnnotationMetadata() { void standardAnnotationMetadata() {
AnnotationMetadata metadata = AnnotationMetadata.introspect(AnnotatedComponent.class); AnnotationMetadata metadata = AnnotationMetadata.introspect(AnnotatedComponent.class);
@ -73,7 +70,7 @@ class AnnotationMetadataTests {
@Test @Test
void standardAnnotationMetadataForSubclass() { void standardAnnotationMetadataForSubclass() {
AnnotationMetadata metadata = AnnotationMetadata.introspect(AnnotatedComponentSubClass.class); AnnotationMetadata metadata = AnnotationMetadata.introspect(AnnotatedComponentSubClass.class);
doTestSubClassAnnotationInfo(metadata); doTestSubClassAnnotationInfo(metadata, false);
} }
@Test @Test
@ -81,10 +78,10 @@ class AnnotationMetadataTests {
MetadataReaderFactory metadataReaderFactory = new SimpleMetadataReaderFactory(); MetadataReaderFactory metadataReaderFactory = new SimpleMetadataReaderFactory();
MetadataReader metadataReader = metadataReaderFactory.getMetadataReader(AnnotatedComponentSubClass.class.getName()); MetadataReader metadataReader = metadataReaderFactory.getMetadataReader(AnnotatedComponentSubClass.class.getName());
AnnotationMetadata metadata = metadataReader.getAnnotationMetadata(); 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.getClassName()).isEqualTo(AnnotatedComponentSubClass.class.getName());
assertThat(metadata.isInterface()).isFalse(); assertThat(metadata.isInterface()).isFalse();
assertThat(metadata.isAnnotation()).isFalse(); assertThat(metadata.isAnnotation()).isFalse();
@ -97,16 +94,16 @@ class AnnotationMetadataTests {
assertThat(metadata.isAnnotated(Scope.class.getName())).isFalse(); assertThat(metadata.isAnnotated(Scope.class.getName())).isFalse();
assertThat(metadata.isAnnotated(SpecialAttr.class.getName())).isFalse(); assertThat(metadata.isAnnotated(SpecialAttr.class.getName())).isFalse();
if (reproduceGh24077) { if (asm) {
assertThat(metadata.isAnnotated(NamedComposedAnnotation.class.getName())).isTrue();
assertThat(metadata.hasAnnotation(NamedComposedAnnotation.class.getName())).isTrue();
assertThat(metadata.getAnnotationTypes()).containsExactly(NamedComposedAnnotation.class.getName());
}
else {
assertThat(metadata.isAnnotated(NamedComposedAnnotation.class.getName())).isFalse(); assertThat(metadata.isAnnotated(NamedComposedAnnotation.class.getName())).isFalse();
assertThat(metadata.hasAnnotation(NamedComposedAnnotation.class.getName())).isFalse(); assertThat(metadata.hasAnnotation(NamedComposedAnnotation.class.getName())).isFalse();
assertThat(metadata.getAnnotationTypes()).isEmpty(); 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(Component.class.getName())).isFalse();
assertThat(metadata.hasAnnotation(Scope.class.getName())).isFalse(); assertThat(metadata.hasAnnotation(Scope.class.getName())).isFalse();
@ -252,7 +249,7 @@ class AnnotationMetadataTests {
@Test @Test
void inheritedAnnotationWithMetaAnnotationsWithIdenticalAttributeNamesUsingStandardAnnotationMetadata() { void inheritedAnnotationWithMetaAnnotationsWithIdenticalAttributeNamesUsingStandardAnnotationMetadata() {
AnnotationMetadata metadata = AnnotationMetadata.introspect(NamedComposedAnnotationExtended.class); AnnotationMetadata metadata = AnnotationMetadata.introspect(NamedComposedAnnotationExtended.class);
assertThat(metadata.hasAnnotation(NamedComposedAnnotation.class.getName())).isFalse(); assertThat(metadata.hasAnnotation(NamedComposedAnnotation.class.getName())).isTrue();
} }
@Test @Test
@ -294,29 +291,18 @@ class AnnotationMetadataTests {
assertThat(metadata.isAnnotated(Component.class.getName())).isTrue(); 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(Component.class.getName())).isTrue();
assertThat(metadata.hasAnnotation(Scope.class.getName())).isTrue(); assertThat(metadata.hasAnnotation(Scope.class.getName())).isTrue();
assertThat(metadata.hasAnnotation(SpecialAttr.class.getName())).isTrue(); assertThat(metadata.hasAnnotation(SpecialAttr.class.getName())).isTrue();
if (reproduceGh24077) {
assertThat(metadata.hasAnnotation(NamedComposedAnnotation.class.getName())).isTrue(); assertThat(metadata.hasAnnotation(NamedComposedAnnotation.class.getName())).isTrue();
assertThat(metadata.getAnnotationTypes()).containsExactlyInAnyOrder( assertThat(metadata.getAnnotationTypes()).containsExactlyInAnyOrder(
Component.class.getName(), Scope.class.getName(), Component.class.getName(), Scope.class.getName(),
SpecialAttr.class.getName(), DirectAnnotation.class.getName(), SpecialAttr.class.getName(), DirectAnnotation.class.getName(),
MetaMetaAnnotation.class.getName(), EnumSubclasses.class.getName(), MetaMetaAnnotation.class.getName(), EnumSubclasses.class.getName(),
NamedComposedAnnotation.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());
}
AnnotationAttributes compAttrs = (AnnotationAttributes) metadata.getAnnotationAttributes(Component.class.getName()); AnnotationAttributes compAttrs = (AnnotationAttributes) metadata.getAnnotationAttributes(Component.class.getName());
assertThat(compAttrs).hasSize(1); assertThat(compAttrs).hasSize(1);
@ -513,6 +499,7 @@ class AnnotationMetadataTests {
@DirectAnnotation(value = "direct", additional = "", additionalArray = {}) @DirectAnnotation(value = "direct", additional = "", additionalArray = {})
@MetaMetaAnnotation @MetaMetaAnnotation
@EnumSubclasses({SubclassEnum.FOO, SubclassEnum.BAR}) @EnumSubclasses({SubclassEnum.FOO, SubclassEnum.BAR})
@NamedComposedAnnotation
private static class AnnotatedComponent implements Serializable { private static class AnnotatedComponent implements Serializable {
@TestAutowired @TestAutowired