Skip to content

Commit 42a61b9

Browse files
committed
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
1 parent 1fe394f commit 42a61b9

File tree

4 files changed

+36
-59
lines changed

4 files changed

+36
-59
lines changed

spring-core/src/main/java/org/springframework/core/annotation/AnnotationsScanner.java

+1-3
Original file line numberDiff line numberDiff line change
@@ -107,7 +107,6 @@ private static <C, R> R processClass(C context, Class<?> source, SearchStrategy
107107
case INHERITED_ANNOTATIONS -> processClassInheritedAnnotations(context, source, searchStrategy, processor);
108108
case SUPERCLASS -> processClassHierarchy(context, source, processor, false, Search.never);
109109
case TYPE_HIERARCHY -> processClassHierarchy(context, source, processor, true, searchEnclosingClass);
110-
case TYPE_HIERARCHY_AND_ENCLOSING_CLASSES -> processClassHierarchy(context, source, processor, true, Search.always);
111110
};
112111
}
113112

@@ -246,8 +245,7 @@ private static <C, R> R processMethod(C context, Method source,
246245
case DIRECT, INHERITED_ANNOTATIONS -> processMethodInheritedAnnotations(context, source, processor);
247246
case SUPERCLASS -> processMethodHierarchy(context, new int[]{0}, source.getDeclaringClass(),
248247
processor, source, false);
249-
case TYPE_HIERARCHY, TYPE_HIERARCHY_AND_ENCLOSING_CLASSES -> processMethodHierarchy(context, new int[]{0},
250-
source.getDeclaringClass(),
248+
case TYPE_HIERARCHY -> processMethodHierarchy(context, new int[]{0}, source.getDeclaringClass(),
251249
processor, source, true);
252250
};
253251
}

spring-core/src/main/java/org/springframework/core/annotation/MergedAnnotations.java

+2-26
Original file line numberDiff line numberDiff line change
@@ -356,10 +356,7 @@ static MergedAnnotations from(AnnotatedElement element, SearchStrategy searchStr
356356
static MergedAnnotations from(AnnotatedElement element, SearchStrategy searchStrategy,
357357
RepeatableContainers repeatableContainers, AnnotationFilter annotationFilter) {
358358

359-
Predicate<Class<?>> searchEnclosingClass =
360-
(searchStrategy == SearchStrategy.TYPE_HIERARCHY_AND_ENCLOSING_CLASSES ?
361-
Search.always : Search.never);
362-
return from(element, searchStrategy, searchEnclosingClass, repeatableContainers, annotationFilter);
359+
return from(element, searchStrategy, Search.never, repeatableContainers, annotationFilter);
363360
}
364361

365362
private static MergedAnnotations from(AnnotatedElement element, SearchStrategy searchStrategy,
@@ -668,28 +665,7 @@ enum SearchStrategy {
668665
* <p>Superclass and enclosing class annotations do not need to be
669666
* meta-annotated with {@link Inherited @Inherited}.
670667
*/
671-
TYPE_HIERARCHY,
672-
673-
/**
674-
* Perform a full search of the entire type hierarchy on the source
675-
* <em>and</em> any enclosing classes.
676-
* <p>This strategy is similar to {@link #TYPE_HIERARCHY} except that
677-
* {@linkplain Class#getEnclosingClass() enclosing classes} are also
678-
* searched.
679-
* <p>Superclass and enclosing class annotations do not need to be
680-
* meta-annotated with {@link Inherited @Inherited}.
681-
* <p>When searching a {@link Method} source, this strategy is identical
682-
* to {@link #TYPE_HIERARCHY}.
683-
* <p><strong>WARNING:</strong> This strategy searches recursively for
684-
* annotations on the enclosing class for any source type, regardless
685-
* whether the source type is an <em>inner class</em>, a {@code static}
686-
* nested class, or a nested interface. Thus, it may find more annotations
687-
* than you would expect.
688-
* @deprecated as of Spring Framework 6.0 M3, for potential removal or
689-
* replacement before 6.0 GA
690-
*/
691-
@Deprecated
692-
TYPE_HIERARCHY_AND_ENCLOSING_CLASSES
668+
TYPE_HIERARCHY
693669

694670
}
695671

spring-core/src/test/java/org/springframework/core/annotation/AnnotationsScannerTests.java

+33-14
Original file line numberDiff line numberDiff line change
@@ -26,13 +26,15 @@
2626
import java.util.Arrays;
2727
import java.util.List;
2828
import java.util.Objects;
29+
import java.util.function.Predicate;
2930
import java.util.stream.Stream;
3031

3132
import org.junit.jupiter.api.Test;
3233

3334
import org.springframework.core.annotation.MergedAnnotations.Search;
3435
import org.springframework.core.annotation.MergedAnnotations.SearchStrategy;
3536
import org.springframework.lang.Nullable;
37+
import org.springframework.util.ClassUtils;
3638
import org.springframework.util.ReflectionUtils;
3739

3840
import static org.assertj.core.api.Assertions.assertThat;
@@ -422,29 +424,34 @@ void typeHierarchyStrategyOnMethodWithGenericParameterNonOverrideScansAnnotation
422424
}
423425

424426
@Test
425-
@SuppressWarnings("deprecation")
426-
void typeHierarchyWithEnclosedStrategyOnEnclosedStaticClassScansAnnotations() {
427+
void typeHierarchyStrategyWithEnclosingClassPredicatesOnEnclosedStaticClassScansAnnotations() {
427428
Class<?> source = AnnotationEnclosingClassSample.EnclosedStatic.EnclosedStaticStatic.class;
428-
assertThat(scan(source, SearchStrategy.TYPE_HIERARCHY_AND_ENCLOSING_CLASSES))
429+
assertThat(scan(source, SearchStrategy.TYPE_HIERARCHY, ClassUtils::isInnerClass))
430+
.containsExactly("0:EnclosedThree");
431+
assertThat(scan(source, SearchStrategy.TYPE_HIERARCHY, Search.always).toList())
432+
.isEqualTo(scan(source, SearchStrategy.TYPE_HIERARCHY, ClassUtils::isStaticClass).toList())
429433
.containsExactly("0:EnclosedThree", "1:EnclosedTwo", "2:EnclosedOne");
430434
}
431435

432436
@Test
433-
@SuppressWarnings("deprecation")
434-
void typeHierarchyWithEnclosedStrategyOnEnclosedInnerClassScansAnnotations() {
437+
void typeHierarchyStrategyWithEnclosingClassPredicatesOnEnclosedInnerClassScansAnnotations() {
435438
Class<?> source = AnnotationEnclosingClassSample.EnclosedInner.EnclosedInnerInner.class;
436-
assertThat(scan(source, SearchStrategy.TYPE_HIERARCHY_AND_ENCLOSING_CLASSES))
439+
assertThat(scan(source, SearchStrategy.TYPE_HIERARCHY, ClassUtils::isStaticClass))
440+
.containsExactly("0:EnclosedThree");
441+
assertThat(scan(source, SearchStrategy.TYPE_HIERARCHY, Search.always).toList())
442+
.isEqualTo(scan(source, SearchStrategy.TYPE_HIERARCHY, ClassUtils::isInnerClass).toList())
437443
.containsExactly("0:EnclosedThree", "1:EnclosedTwo", "2:EnclosedOne");
438444
}
439445

440446
@Test
441-
@SuppressWarnings("deprecation")
442-
void typeHierarchyWithEnclosedStrategyOnMethodHierarchyUsesTypeHierarchyScan() {
447+
void typeHierarchyStrategyWithEnclosingClassPredicatesOnMethodHierarchyUsesTypeHierarchyScan() {
443448
Method source = methodFrom(WithHierarchy.class);
444-
assertThat(scan(source, SearchStrategy.TYPE_HIERARCHY_AND_ENCLOSING_CLASSES)).containsExactly(
445-
"0:TestAnnotation1", "1:TestAnnotation5", "1:TestInheritedAnnotation5",
446-
"2:TestAnnotation6", "3:TestAnnotation2", "3:TestInheritedAnnotation2",
447-
"4:TestAnnotation3", "5:TestAnnotation4");
449+
assertThat(scan(source, SearchStrategy.TYPE_HIERARCHY, Search.always).toList())
450+
.isEqualTo(scan(source, SearchStrategy.TYPE_HIERARCHY, ClassUtils::isInnerClass).toList())
451+
.containsExactly(
452+
"0:TestAnnotation1", "1:TestAnnotation5", "1:TestInheritedAnnotation5",
453+
"2:TestAnnotation6", "3:TestAnnotation2", "3:TestInheritedAnnotation2",
454+
"4:TestAnnotation3", "5:TestAnnotation4");
448455
}
449456

450457
@Test
@@ -509,8 +516,14 @@ private Method methodFrom(Class<?> type) {
509516
}
510517

511518
private Stream<String> scan(AnnotatedElement element, SearchStrategy searchStrategy) {
519+
return scan(element, searchStrategy, Search.never);
520+
}
521+
522+
private Stream<String> scan(AnnotatedElement element, SearchStrategy searchStrategy,
523+
Predicate<Class<?>> searchEnclosingClass) {
524+
512525
List<String> results = new ArrayList<>();
513-
scan(this, element, searchStrategy,
526+
scan(this, element, searchStrategy, searchEnclosingClass,
514527
(criteria, aggregateIndex, source, annotations) -> {
515528
trackIndexedAnnotations(aggregateIndex, annotations, results);
516529
return null; // continue searching
@@ -521,7 +534,13 @@ private Stream<String> scan(AnnotatedElement element, SearchStrategy searchStrat
521534
private static <C, R> R scan(C context, AnnotatedElement source, SearchStrategy searchStrategy,
522535
AnnotationsProcessor<C, R> processor) {
523536

524-
return AnnotationsScanner.scan(context, source, searchStrategy, Search.never, processor);
537+
return scan(context, source, searchStrategy, Search.never, processor);
538+
}
539+
540+
private static <C, R> R scan(C context, AnnotatedElement source, SearchStrategy searchStrategy,
541+
Predicate<Class<?>> searchEnclosingClass, AnnotationsProcessor<C, R> processor) {
542+
543+
return AnnotationsScanner.scan(context, source, searchStrategy, searchEnclosingClass, processor);
525544
}
526545

527546
private void trackIndexedAnnotations(int aggregateIndex, Annotation[] annotations, List<String> results) {

spring-core/src/test/java/org/springframework/core/annotation/MergedAnnotationsTests.java

-16
Original file line numberDiff line numberDiff line change
@@ -843,22 +843,6 @@ void streamTypeHierarchyFromClassWithInterface() throws Exception {
843843
Transactional.class)).hasSize(1);
844844
}
845845

846-
@Test
847-
@SuppressWarnings("deprecation")
848-
void streamTypeHierarchyAndEnclosingClassesFromNonAnnotatedInnerClassWithAnnotatedEnclosingClass() {
849-
Stream<Class<?>> classes = MergedAnnotations.from(AnnotatedClass.NonAnnotatedInnerClass.class,
850-
SearchStrategy.TYPE_HIERARCHY_AND_ENCLOSING_CLASSES).stream().map(MergedAnnotation::getType);
851-
assertThat(classes).containsExactly(Component.class, Indexed.class);
852-
}
853-
854-
@Test
855-
@SuppressWarnings("deprecation")
856-
void streamTypeHierarchyAndEnclosingClassesFromNonAnnotatedStaticNestedClassWithAnnotatedEnclosingClass() {
857-
Stream<Class<?>> classes = MergedAnnotations.from(AnnotatedClass.NonAnnotatedStaticNestedClass.class,
858-
SearchStrategy.TYPE_HIERARCHY_AND_ENCLOSING_CLASSES).stream().map(MergedAnnotation::getType);
859-
assertThat(classes).containsExactly(Component.class, Indexed.class);
860-
}
861-
862846
@Test
863847
@SuppressWarnings("deprecation")
864848
void getFromMethodWithMethodAnnotationOnLeaf() throws Exception {

0 commit comments

Comments
 (0)