Remove deprecated "enclosing classes" search strategy for MergedAnnotations

Closes gh-28080
This commit is contained in:
Sam Brannen 2022-02-19 17:25:50 +01:00
parent ad3095f197
commit 819d4256b7
4 changed files with 12 additions and 93 deletions

View File

@ -99,9 +99,8 @@ abstract class AnnotationsScanner {
return switch (searchStrategy) {
case DIRECT -> processElement(context, source, processor);
case INHERITED_ANNOTATIONS -> processClassInheritedAnnotations(context, source, searchStrategy, processor);
case SUPERCLASS -> processClassHierarchy(context, source, processor, false, false);
case TYPE_HIERARCHY -> processClassHierarchy(context, source, processor, true, false);
case TYPE_HIERARCHY_AND_ENCLOSING_CLASSES -> processClassHierarchy(context, source, processor, true, true);
case SUPERCLASS -> processClassHierarchy(context, source, processor, false);
case TYPE_HIERARCHY -> processClassHierarchy(context, source, processor, true);
};
}
@ -161,15 +160,14 @@ abstract class AnnotationsScanner {
@Nullable
private static <C, R> R processClassHierarchy(C context, Class<?> source,
AnnotationsProcessor<C, R> processor, boolean includeInterfaces, boolean includeEnclosing) {
AnnotationsProcessor<C, R> processor, boolean includeInterfaces) {
return processClassHierarchy(context, new int[] {0}, source, processor,
includeInterfaces, includeEnclosing);
return processClassHierarchy(context, new int[] {0}, source, processor, includeInterfaces);
}
@Nullable
private static <C, R> R processClassHierarchy(C context, int[] aggregateIndex, Class<?> source,
AnnotationsProcessor<C, R> processor, boolean includeInterfaces, boolean includeEnclosing) {
AnnotationsProcessor<C, R> processor, boolean includeInterfaces) {
try {
R result = processor.doWithAggregate(context, aggregateIndex[0]);
@ -188,7 +186,7 @@ abstract class AnnotationsScanner {
if (includeInterfaces) {
for (Class<?> interfaceType : source.getInterfaces()) {
R interfacesResult = processClassHierarchy(context, aggregateIndex,
interfaceType, processor, true, includeEnclosing);
interfaceType, processor, true);
if (interfacesResult != null) {
return interfacesResult;
}
@ -197,31 +195,11 @@ abstract class AnnotationsScanner {
Class<?> superclass = source.getSuperclass();
if (superclass != Object.class && superclass != null) {
R superclassResult = processClassHierarchy(context, aggregateIndex,
superclass, processor, includeInterfaces, includeEnclosing);
superclass, processor, includeInterfaces);
if (superclassResult != null) {
return superclassResult;
}
}
if (includeEnclosing) {
// Since merely attempting to load the enclosing class may result in
// automatic loading of sibling nested classes that in turn results
// in an exception such as NoClassDefFoundError, we wrap the following
// in its own dedicated try-catch block in order not to preemptively
// halt the annotation scanning process.
try {
Class<?> enclosingClass = source.getEnclosingClass();
if (enclosingClass != null) {
R enclosingResult = processClassHierarchy(context, aggregateIndex,
enclosingClass, processor, includeInterfaces, true);
if (enclosingResult != null) {
return enclosingResult;
}
}
}
catch (Throwable ex) {
AnnotationUtils.handleIntrospectionFailure(source, ex);
}
}
}
catch (Throwable ex) {
AnnotationUtils.handleIntrospectionFailure(source, ex);
@ -238,8 +216,7 @@ abstract class AnnotationsScanner {
case DIRECT, INHERITED_ANNOTATIONS -> processMethodInheritedAnnotations(context, source, processor);
case SUPERCLASS -> processMethodHierarchy(context, new int[]{0}, source.getDeclaringClass(),
processor, source, false);
case TYPE_HIERARCHY, TYPE_HIERARCHY_AND_ENCLOSING_CLASSES -> processMethodHierarchy(context, new int[]{0},
source.getDeclaringClass(),
case TYPE_HIERARCHY -> processMethodHierarchy(context, new int[]{0}, source.getDeclaringClass(),
processor, source, true);
};
}
@ -506,12 +483,8 @@ abstract class AnnotationsScanner {
if (source == Object.class) {
return true;
}
if (source instanceof Class) {
Class<?> sourceClass = (Class<?>) source;
boolean noSuperTypes = (sourceClass.getSuperclass() == Object.class &&
sourceClass.getInterfaces().length == 0);
return (searchStrategy == SearchStrategy.TYPE_HIERARCHY_AND_ENCLOSING_CLASSES ? noSuperTypes &&
sourceClass.getEnclosingClass() == null : noSuperTypes);
if (source instanceof Class<?> sourceClass) {
return (sourceClass.getSuperclass() == Object.class && sourceClass.getInterfaces().length == 0);
}
if (source instanceof Method sourceMethod) {
return (Modifier.isPrivate(sourceMethod.getModifiers()) ||

View File

@ -1,5 +1,5 @@
/*
* Copyright 2002-2020 the original author or authors.
* Copyright 2002-2022 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@ -472,20 +472,8 @@ public interface MergedAnnotations extends Iterable<MergedAnnotation<Annotation>
* superclasses and implemented interfaces. Superclass annotations do
* not need to be meta-annotated with {@link Inherited @Inherited}.
*/
TYPE_HIERARCHY,
TYPE_HIERARCHY
/**
* Perform a full search of the entire type hierarchy on the source
* <em>and</em> any enclosing classes. This strategy is similar to
* {@link #TYPE_HIERARCHY} except that {@linkplain Class#getEnclosingClass()
* enclosing classes} are also searched. Superclass annotations do not
* need to be meta-annotated with {@link Inherited @Inherited}. When
* searching a {@link Method} source, this strategy is identical to
* {@link #TYPE_HIERARCHY}.
* @deprecated as of Spring Framework 5.3.17; to be removed in Spring Framework 6.0
*/
@Deprecated
TYPE_HIERARCHY_AND_ENCLOSING_CLASSES
}
}

View File

@ -420,32 +420,6 @@ class AnnotationsScannerTests {
assertThat(scan(source, SearchStrategy.TYPE_HIERARCHY)).containsExactly("0:TestAnnotation1");
}
@Test
@SuppressWarnings("deprecation")
void typeHierarchyWithEnclosedStrategyOnEnclosedStaticClassScansAnnotations() {
Class<?> source = AnnotationEnclosingClassSample.EnclosedStatic.EnclosedStaticStatic.class;
assertThat(scan(source, SearchStrategy.TYPE_HIERARCHY_AND_ENCLOSING_CLASSES))
.containsExactly("0:EnclosedThree", "1:EnclosedTwo", "2:EnclosedOne");
}
@Test
@SuppressWarnings("deprecation")
void typeHierarchyWithEnclosedStrategyOnEnclosedInnerClassScansAnnotations() {
Class<?> source = AnnotationEnclosingClassSample.EnclosedInner.EnclosedInnerInner.class;
assertThat(scan(source, SearchStrategy.TYPE_HIERARCHY_AND_ENCLOSING_CLASSES))
.containsExactly("0:EnclosedThree", "1:EnclosedTwo", "2:EnclosedOne");
}
@Test
@SuppressWarnings("deprecation")
void typeHierarchyWithEnclosedStrategyOnMethodHierarchyUsesTypeHierarchyScan() {
Method source = methodFrom(WithHierarchy.class);
assertThat(scan(source, SearchStrategy.TYPE_HIERARCHY_AND_ENCLOSING_CLASSES)).containsExactly(
"0:TestAnnotation1", "1:TestAnnotation5", "1:TestInheritedAnnotation5",
"2:TestAnnotation6", "3:TestAnnotation2", "3:TestInheritedAnnotation2",
"4:TestAnnotation3", "5:TestAnnotation4");
}
@Test
void scanWhenProcessorReturnsFromDoWithAggregateExitsEarly() {
String result = AnnotationsScanner.scan(this, WithSingleSuperclass.class,

View File

@ -710,22 +710,6 @@ class MergedAnnotationsTests {
Transactional.class)).hasSize(1);
}
@Test
@SuppressWarnings("deprecation")
void streamTypeHierarchyAndEnclosingClassesFromNonAnnotatedInnerClassWithAnnotatedEnclosingClass() {
Stream<Class<?>> classes = MergedAnnotations.from(AnnotatedClass.NonAnnotatedInnerClass.class,
SearchStrategy.TYPE_HIERARCHY_AND_ENCLOSING_CLASSES).stream().map(MergedAnnotation::getType);
assertThat(classes).containsExactly(Component.class, Indexed.class);
}
@Test
@SuppressWarnings("deprecation")
void streamTypeHierarchyAndEnclosingClassesFromNonAnnotatedStaticNestedClassWithAnnotatedEnclosingClass() {
Stream<Class<?>> classes = MergedAnnotations.from(AnnotatedClass.NonAnnotatedStaticNestedClass.class,
SearchStrategy.TYPE_HIERARCHY_AND_ENCLOSING_CLASSES).stream().map(MergedAnnotation::getType);
assertThat(classes).containsExactly(Component.class, Indexed.class);
}
@Test
void getFromMethodWithMethodAnnotationOnLeaf() throws Exception {
Method method = Leaf.class.getMethod("annotatedOnLeaf");