Remove TYPE_HIERARCHY_AND_ENCLOSING_CLASSES strategy for MergedAnnotations
This commit removes the deprecated TYPE_HIERARCHY_AND_ENCLOSING_CLASSES search strategy from the MergedAnnotations model. As a direct replacement for the TYPE_HIERARCHY_AND_ENCLOSING_CLASSES search strategy, users can use the new fluent search API as follows. MergedAnnotations mergedAnnotations = MergedAnnotations.search(TYPE_HIERARCHY) .withEnclosingClasses(clazz -> true) // always search enclosing classes .from(MyClass.class); Note, however, that users are highly encouraged to use ClassUtils::isInnerClass, ClassUtils::isStaticClass, or a custom predicate other than `clazz -> true`. Closes gh-28080
This commit is contained in:
parent
1fe394f11d
commit
42a61b966b
|
@ -107,7 +107,6 @@ abstract class AnnotationsScanner {
|
||||||
case INHERITED_ANNOTATIONS -> processClassInheritedAnnotations(context, source, searchStrategy, processor);
|
case INHERITED_ANNOTATIONS -> processClassInheritedAnnotations(context, source, searchStrategy, processor);
|
||||||
case SUPERCLASS -> processClassHierarchy(context, source, processor, false, Search.never);
|
case SUPERCLASS -> processClassHierarchy(context, source, processor, false, Search.never);
|
||||||
case TYPE_HIERARCHY -> processClassHierarchy(context, source, processor, true, searchEnclosingClass);
|
case TYPE_HIERARCHY -> processClassHierarchy(context, source, processor, true, searchEnclosingClass);
|
||||||
case TYPE_HIERARCHY_AND_ENCLOSING_CLASSES -> processClassHierarchy(context, source, processor, true, Search.always);
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -246,8 +245,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);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
@ -356,10 +356,7 @@ public interface MergedAnnotations extends Iterable<MergedAnnotation<Annotation>
|
||||||
static MergedAnnotations from(AnnotatedElement element, SearchStrategy searchStrategy,
|
static MergedAnnotations from(AnnotatedElement element, SearchStrategy searchStrategy,
|
||||||
RepeatableContainers repeatableContainers, AnnotationFilter annotationFilter) {
|
RepeatableContainers repeatableContainers, AnnotationFilter annotationFilter) {
|
||||||
|
|
||||||
Predicate<Class<?>> searchEnclosingClass =
|
return from(element, searchStrategy, Search.never, repeatableContainers, annotationFilter);
|
||||||
(searchStrategy == SearchStrategy.TYPE_HIERARCHY_AND_ENCLOSING_CLASSES ?
|
|
||||||
Search.always : Search.never);
|
|
||||||
return from(element, searchStrategy, searchEnclosingClass, repeatableContainers, annotationFilter);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static MergedAnnotations from(AnnotatedElement element, SearchStrategy searchStrategy,
|
private static MergedAnnotations from(AnnotatedElement element, SearchStrategy searchStrategy,
|
||||||
|
@ -668,28 +665,7 @@ public interface MergedAnnotations extends Iterable<MergedAnnotation<Annotation>
|
||||||
* <p>Superclass and enclosing class annotations do not need to be
|
* <p>Superclass and enclosing class annotations do not need to be
|
||||||
* meta-annotated with {@link Inherited @Inherited}.
|
* 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.
|
|
||||||
* <p>This strategy is similar to {@link #TYPE_HIERARCHY} except that
|
|
||||||
* {@linkplain Class#getEnclosingClass() enclosing classes} are also
|
|
||||||
* searched.
|
|
||||||
* <p>Superclass and enclosing class annotations do not need to be
|
|
||||||
* meta-annotated with {@link Inherited @Inherited}.
|
|
||||||
* <p>When searching a {@link Method} source, this strategy is identical
|
|
||||||
* to {@link #TYPE_HIERARCHY}.
|
|
||||||
* <p><strong>WARNING:</strong> This strategy searches recursively for
|
|
||||||
* annotations on the enclosing class for any source type, regardless
|
|
||||||
* whether the source type is an <em>inner class</em>, a {@code static}
|
|
||||||
* nested class, or a nested interface. Thus, it may find more annotations
|
|
||||||
* than you would expect.
|
|
||||||
* @deprecated as of Spring Framework 6.0 M3, for potential removal or
|
|
||||||
* replacement before 6.0 GA
|
|
||||||
*/
|
|
||||||
@Deprecated
|
|
||||||
TYPE_HIERARCHY_AND_ENCLOSING_CLASSES
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -26,6 +26,7 @@ import java.util.ArrayList;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
|
import java.util.function.Predicate;
|
||||||
import java.util.stream.Stream;
|
import java.util.stream.Stream;
|
||||||
|
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
|
@ -33,6 +34,7 @@ import org.junit.jupiter.api.Test;
|
||||||
import org.springframework.core.annotation.MergedAnnotations.Search;
|
import org.springframework.core.annotation.MergedAnnotations.Search;
|
||||||
import org.springframework.core.annotation.MergedAnnotations.SearchStrategy;
|
import org.springframework.core.annotation.MergedAnnotations.SearchStrategy;
|
||||||
import org.springframework.lang.Nullable;
|
import org.springframework.lang.Nullable;
|
||||||
|
import org.springframework.util.ClassUtils;
|
||||||
import org.springframework.util.ReflectionUtils;
|
import org.springframework.util.ReflectionUtils;
|
||||||
|
|
||||||
import static org.assertj.core.api.Assertions.assertThat;
|
import static org.assertj.core.api.Assertions.assertThat;
|
||||||
|
@ -422,29 +424,34 @@ class AnnotationsScannerTests {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@SuppressWarnings("deprecation")
|
void typeHierarchyStrategyWithEnclosingClassPredicatesOnEnclosedStaticClassScansAnnotations() {
|
||||||
void typeHierarchyWithEnclosedStrategyOnEnclosedStaticClassScansAnnotations() {
|
|
||||||
Class<?> source = AnnotationEnclosingClassSample.EnclosedStatic.EnclosedStaticStatic.class;
|
Class<?> source = AnnotationEnclosingClassSample.EnclosedStatic.EnclosedStaticStatic.class;
|
||||||
assertThat(scan(source, SearchStrategy.TYPE_HIERARCHY_AND_ENCLOSING_CLASSES))
|
assertThat(scan(source, SearchStrategy.TYPE_HIERARCHY, ClassUtils::isInnerClass))
|
||||||
|
.containsExactly("0:EnclosedThree");
|
||||||
|
assertThat(scan(source, SearchStrategy.TYPE_HIERARCHY, Search.always).toList())
|
||||||
|
.isEqualTo(scan(source, SearchStrategy.TYPE_HIERARCHY, ClassUtils::isStaticClass).toList())
|
||||||
.containsExactly("0:EnclosedThree", "1:EnclosedTwo", "2:EnclosedOne");
|
.containsExactly("0:EnclosedThree", "1:EnclosedTwo", "2:EnclosedOne");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@SuppressWarnings("deprecation")
|
void typeHierarchyStrategyWithEnclosingClassPredicatesOnEnclosedInnerClassScansAnnotations() {
|
||||||
void typeHierarchyWithEnclosedStrategyOnEnclosedInnerClassScansAnnotations() {
|
|
||||||
Class<?> source = AnnotationEnclosingClassSample.EnclosedInner.EnclosedInnerInner.class;
|
Class<?> source = AnnotationEnclosingClassSample.EnclosedInner.EnclosedInnerInner.class;
|
||||||
assertThat(scan(source, SearchStrategy.TYPE_HIERARCHY_AND_ENCLOSING_CLASSES))
|
assertThat(scan(source, SearchStrategy.TYPE_HIERARCHY, ClassUtils::isStaticClass))
|
||||||
|
.containsExactly("0:EnclosedThree");
|
||||||
|
assertThat(scan(source, SearchStrategy.TYPE_HIERARCHY, Search.always).toList())
|
||||||
|
.isEqualTo(scan(source, SearchStrategy.TYPE_HIERARCHY, ClassUtils::isInnerClass).toList())
|
||||||
.containsExactly("0:EnclosedThree", "1:EnclosedTwo", "2:EnclosedOne");
|
.containsExactly("0:EnclosedThree", "1:EnclosedTwo", "2:EnclosedOne");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@SuppressWarnings("deprecation")
|
void typeHierarchyStrategyWithEnclosingClassPredicatesOnMethodHierarchyUsesTypeHierarchyScan() {
|
||||||
void typeHierarchyWithEnclosedStrategyOnMethodHierarchyUsesTypeHierarchyScan() {
|
|
||||||
Method source = methodFrom(WithHierarchy.class);
|
Method source = methodFrom(WithHierarchy.class);
|
||||||
assertThat(scan(source, SearchStrategy.TYPE_HIERARCHY_AND_ENCLOSING_CLASSES)).containsExactly(
|
assertThat(scan(source, SearchStrategy.TYPE_HIERARCHY, Search.always).toList())
|
||||||
"0:TestAnnotation1", "1:TestAnnotation5", "1:TestInheritedAnnotation5",
|
.isEqualTo(scan(source, SearchStrategy.TYPE_HIERARCHY, ClassUtils::isInnerClass).toList())
|
||||||
"2:TestAnnotation6", "3:TestAnnotation2", "3:TestInheritedAnnotation2",
|
.containsExactly(
|
||||||
"4:TestAnnotation3", "5:TestAnnotation4");
|
"0:TestAnnotation1", "1:TestAnnotation5", "1:TestInheritedAnnotation5",
|
||||||
|
"2:TestAnnotation6", "3:TestAnnotation2", "3:TestInheritedAnnotation2",
|
||||||
|
"4:TestAnnotation3", "5:TestAnnotation4");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
@ -509,8 +516,14 @@ class AnnotationsScannerTests {
|
||||||
}
|
}
|
||||||
|
|
||||||
private Stream<String> scan(AnnotatedElement element, SearchStrategy searchStrategy) {
|
private Stream<String> scan(AnnotatedElement element, SearchStrategy searchStrategy) {
|
||||||
|
return scan(element, searchStrategy, Search.never);
|
||||||
|
}
|
||||||
|
|
||||||
|
private Stream<String> scan(AnnotatedElement element, SearchStrategy searchStrategy,
|
||||||
|
Predicate<Class<?>> searchEnclosingClass) {
|
||||||
|
|
||||||
List<String> results = new ArrayList<>();
|
List<String> results = new ArrayList<>();
|
||||||
scan(this, element, searchStrategy,
|
scan(this, element, searchStrategy, searchEnclosingClass,
|
||||||
(criteria, aggregateIndex, source, annotations) -> {
|
(criteria, aggregateIndex, source, annotations) -> {
|
||||||
trackIndexedAnnotations(aggregateIndex, annotations, results);
|
trackIndexedAnnotations(aggregateIndex, annotations, results);
|
||||||
return null; // continue searching
|
return null; // continue searching
|
||||||
|
@ -521,7 +534,13 @@ class AnnotationsScannerTests {
|
||||||
private static <C, R> R scan(C context, AnnotatedElement source, SearchStrategy searchStrategy,
|
private static <C, R> R scan(C context, AnnotatedElement source, SearchStrategy searchStrategy,
|
||||||
AnnotationsProcessor<C, R> processor) {
|
AnnotationsProcessor<C, R> processor) {
|
||||||
|
|
||||||
return AnnotationsScanner.scan(context, source, searchStrategy, Search.never, processor);
|
return scan(context, source, searchStrategy, Search.never, processor);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static <C, R> R scan(C context, AnnotatedElement source, SearchStrategy searchStrategy,
|
||||||
|
Predicate<Class<?>> searchEnclosingClass, AnnotationsProcessor<C, R> processor) {
|
||||||
|
|
||||||
|
return AnnotationsScanner.scan(context, source, searchStrategy, searchEnclosingClass, processor);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void trackIndexedAnnotations(int aggregateIndex, Annotation[] annotations, List<String> results) {
|
private void trackIndexedAnnotations(int aggregateIndex, Annotation[] annotations, List<String> results) {
|
||||||
|
|
|
@ -843,22 +843,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
|
||||||
@SuppressWarnings("deprecation")
|
@SuppressWarnings("deprecation")
|
||||||
void getFromMethodWithMethodAnnotationOnLeaf() throws Exception {
|
void getFromMethodWithMethodAnnotationOnLeaf() throws Exception {
|
||||||
|
|
Loading…
Reference in New Issue