Remove deprecated "enclosing classes" search strategy for MergedAnnotations
Closes gh-28080
This commit is contained in:
parent
ad3095f197
commit
819d4256b7
|
@ -99,9 +99,8 @@ abstract class AnnotationsScanner {
|
||||||
return switch (searchStrategy) {
|
return switch (searchStrategy) {
|
||||||
case DIRECT -> processElement(context, source, processor);
|
case DIRECT -> processElement(context, source, processor);
|
||||||
case INHERITED_ANNOTATIONS -> processClassInheritedAnnotations(context, source, searchStrategy, processor);
|
case INHERITED_ANNOTATIONS -> processClassInheritedAnnotations(context, source, searchStrategy, processor);
|
||||||
case SUPERCLASS -> processClassHierarchy(context, source, processor, false, false);
|
case SUPERCLASS -> processClassHierarchy(context, source, processor, false);
|
||||||
case TYPE_HIERARCHY -> processClassHierarchy(context, source, processor, true, false);
|
case TYPE_HIERARCHY -> processClassHierarchy(context, source, processor, true);
|
||||||
case TYPE_HIERARCHY_AND_ENCLOSING_CLASSES -> processClassHierarchy(context, source, processor, true, true);
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -161,15 +160,14 @@ abstract class AnnotationsScanner {
|
||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
private static <C, R> R processClassHierarchy(C context, Class<?> source,
|
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,
|
return processClassHierarchy(context, new int[] {0}, source, processor, includeInterfaces);
|
||||||
includeInterfaces, includeEnclosing);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
private static <C, R> R processClassHierarchy(C context, int[] aggregateIndex, Class<?> source,
|
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 {
|
try {
|
||||||
R result = processor.doWithAggregate(context, aggregateIndex[0]);
|
R result = processor.doWithAggregate(context, aggregateIndex[0]);
|
||||||
|
@ -188,7 +186,7 @@ abstract class AnnotationsScanner {
|
||||||
if (includeInterfaces) {
|
if (includeInterfaces) {
|
||||||
for (Class<?> interfaceType : source.getInterfaces()) {
|
for (Class<?> interfaceType : source.getInterfaces()) {
|
||||||
R interfacesResult = processClassHierarchy(context, aggregateIndex,
|
R interfacesResult = processClassHierarchy(context, aggregateIndex,
|
||||||
interfaceType, processor, true, includeEnclosing);
|
interfaceType, processor, true);
|
||||||
if (interfacesResult != null) {
|
if (interfacesResult != null) {
|
||||||
return interfacesResult;
|
return interfacesResult;
|
||||||
}
|
}
|
||||||
|
@ -197,31 +195,11 @@ abstract class AnnotationsScanner {
|
||||||
Class<?> superclass = source.getSuperclass();
|
Class<?> superclass = source.getSuperclass();
|
||||||
if (superclass != Object.class && superclass != null) {
|
if (superclass != Object.class && superclass != null) {
|
||||||
R superclassResult = processClassHierarchy(context, aggregateIndex,
|
R superclassResult = processClassHierarchy(context, aggregateIndex,
|
||||||
superclass, processor, includeInterfaces, includeEnclosing);
|
superclass, processor, includeInterfaces);
|
||||||
if (superclassResult != null) {
|
if (superclassResult != null) {
|
||||||
return superclassResult;
|
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) {
|
catch (Throwable ex) {
|
||||||
AnnotationUtils.handleIntrospectionFailure(source, ex);
|
AnnotationUtils.handleIntrospectionFailure(source, ex);
|
||||||
|
@ -238,8 +216,7 @@ abstract class AnnotationsScanner {
|
||||||
case DIRECT, INHERITED_ANNOTATIONS -> processMethodInheritedAnnotations(context, source, processor);
|
case DIRECT, INHERITED_ANNOTATIONS -> processMethodInheritedAnnotations(context, source, processor);
|
||||||
case SUPERCLASS -> processMethodHierarchy(context, new int[]{0}, source.getDeclaringClass(),
|
case SUPERCLASS -> processMethodHierarchy(context, new int[]{0}, source.getDeclaringClass(),
|
||||||
processor, source, false);
|
processor, source, false);
|
||||||
case TYPE_HIERARCHY, TYPE_HIERARCHY_AND_ENCLOSING_CLASSES -> processMethodHierarchy(context, new int[]{0},
|
case TYPE_HIERARCHY -> processMethodHierarchy(context, new int[]{0}, source.getDeclaringClass(),
|
||||||
source.getDeclaringClass(),
|
|
||||||
processor, source, true);
|
processor, source, true);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -506,12 +483,8 @@ abstract class AnnotationsScanner {
|
||||||
if (source == Object.class) {
|
if (source == Object.class) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
if (source instanceof Class) {
|
if (source instanceof Class<?> sourceClass) {
|
||||||
Class<?> sourceClass = (Class<?>) source;
|
return (sourceClass.getSuperclass() == Object.class && sourceClass.getInterfaces().length == 0);
|
||||||
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 Method sourceMethod) {
|
if (source instanceof Method sourceMethod) {
|
||||||
return (Modifier.isPrivate(sourceMethod.getModifiers()) ||
|
return (Modifier.isPrivate(sourceMethod.getModifiers()) ||
|
||||||
|
|
|
@ -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");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with 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
|
* superclasses and implemented interfaces. Superclass annotations do
|
||||||
* not need to be meta-annotated with {@link Inherited @Inherited}.
|
* 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
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -420,32 +420,6 @@ class AnnotationsScannerTests {
|
||||||
assertThat(scan(source, SearchStrategy.TYPE_HIERARCHY)).containsExactly("0:TestAnnotation1");
|
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
|
@Test
|
||||||
void scanWhenProcessorReturnsFromDoWithAggregateExitsEarly() {
|
void scanWhenProcessorReturnsFromDoWithAggregateExitsEarly() {
|
||||||
String result = AnnotationsScanner.scan(this, WithSingleSuperclass.class,
|
String result = AnnotationsScanner.scan(this, WithSingleSuperclass.class,
|
||||||
|
|
|
@ -710,22 +710,6 @@ class MergedAnnotationsTests {
|
||||||
Transactional.class)).hasSize(1);
|
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
|
@Test
|
||||||
void getFromMethodWithMethodAnnotationOnLeaf() throws Exception {
|
void getFromMethodWithMethodAnnotationOnLeaf() throws Exception {
|
||||||
Method method = Leaf.class.getMethod("annotatedOnLeaf");
|
Method method = Leaf.class.getMethod("annotatedOnLeaf");
|
||||||
|
|
Loading…
Reference in New Issue