Skip to content

Commit 819d425

Browse files
committed
Remove deprecated "enclosing classes" search strategy for MergedAnnotations
Closes gh-28080
1 parent ad3095f commit 819d425

File tree

4 files changed

+12
-93
lines changed

4 files changed

+12
-93
lines changed

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

+10-37
Original file line numberDiff line numberDiff line change
@@ -99,9 +99,8 @@ private static <C, R> R processClass(C context, Class<?> source,
9999
return switch (searchStrategy) {
100100
case DIRECT -> processElement(context, source, processor);
101101
case INHERITED_ANNOTATIONS -> processClassInheritedAnnotations(context, source, searchStrategy, processor);
102-
case SUPERCLASS -> processClassHierarchy(context, source, processor, false, false);
103-
case TYPE_HIERARCHY -> processClassHierarchy(context, source, processor, true, false);
104-
case TYPE_HIERARCHY_AND_ENCLOSING_CLASSES -> processClassHierarchy(context, source, processor, true, true);
102+
case SUPERCLASS -> processClassHierarchy(context, source, processor, false);
103+
case TYPE_HIERARCHY -> processClassHierarchy(context, source, processor, true);
105104
};
106105
}
107106

@@ -161,15 +160,14 @@ private static <C, R> R processClassInheritedAnnotations(C context, Class<?> sou
161160

162161
@Nullable
163162
private static <C, R> R processClassHierarchy(C context, Class<?> source,
164-
AnnotationsProcessor<C, R> processor, boolean includeInterfaces, boolean includeEnclosing) {
163+
AnnotationsProcessor<C, R> processor, boolean includeInterfaces) {
165164

166-
return processClassHierarchy(context, new int[] {0}, source, processor,
167-
includeInterfaces, includeEnclosing);
165+
return processClassHierarchy(context, new int[] {0}, source, processor, includeInterfaces);
168166
}
169167

170168
@Nullable
171169
private static <C, R> R processClassHierarchy(C context, int[] aggregateIndex, Class<?> source,
172-
AnnotationsProcessor<C, R> processor, boolean includeInterfaces, boolean includeEnclosing) {
170+
AnnotationsProcessor<C, R> processor, boolean includeInterfaces) {
173171

174172
try {
175173
R result = processor.doWithAggregate(context, aggregateIndex[0]);
@@ -188,7 +186,7 @@ private static <C, R> R processClassHierarchy(C context, int[] aggregateIndex, C
188186
if (includeInterfaces) {
189187
for (Class<?> interfaceType : source.getInterfaces()) {
190188
R interfacesResult = processClassHierarchy(context, aggregateIndex,
191-
interfaceType, processor, true, includeEnclosing);
189+
interfaceType, processor, true);
192190
if (interfacesResult != null) {
193191
return interfacesResult;
194192
}
@@ -197,31 +195,11 @@ private static <C, R> R processClassHierarchy(C context, int[] aggregateIndex, C
197195
Class<?> superclass = source.getSuperclass();
198196
if (superclass != Object.class && superclass != null) {
199197
R superclassResult = processClassHierarchy(context, aggregateIndex,
200-
superclass, processor, includeInterfaces, includeEnclosing);
198+
superclass, processor, includeInterfaces);
201199
if (superclassResult != null) {
202200
return superclassResult;
203201
}
204202
}
205-
if (includeEnclosing) {
206-
// Since merely attempting to load the enclosing class may result in
207-
// automatic loading of sibling nested classes that in turn results
208-
// in an exception such as NoClassDefFoundError, we wrap the following
209-
// in its own dedicated try-catch block in order not to preemptively
210-
// halt the annotation scanning process.
211-
try {
212-
Class<?> enclosingClass = source.getEnclosingClass();
213-
if (enclosingClass != null) {
214-
R enclosingResult = processClassHierarchy(context, aggregateIndex,
215-
enclosingClass, processor, includeInterfaces, true);
216-
if (enclosingResult != null) {
217-
return enclosingResult;
218-
}
219-
}
220-
}
221-
catch (Throwable ex) {
222-
AnnotationUtils.handleIntrospectionFailure(source, ex);
223-
}
224-
}
225203
}
226204
catch (Throwable ex) {
227205
AnnotationUtils.handleIntrospectionFailure(source, ex);
@@ -238,8 +216,7 @@ private static <C, R> R processMethod(C context, Method source,
238216
case DIRECT, INHERITED_ANNOTATIONS -> processMethodInheritedAnnotations(context, source, processor);
239217
case SUPERCLASS -> processMethodHierarchy(context, new int[]{0}, source.getDeclaringClass(),
240218
processor, source, false);
241-
case TYPE_HIERARCHY, TYPE_HIERARCHY_AND_ENCLOSING_CLASSES -> processMethodHierarchy(context, new int[]{0},
242-
source.getDeclaringClass(),
219+
case TYPE_HIERARCHY -> processMethodHierarchy(context, new int[]{0}, source.getDeclaringClass(),
243220
processor, source, true);
244221
};
245222
}
@@ -506,12 +483,8 @@ private static boolean isWithoutHierarchy(AnnotatedElement source, SearchStrateg
506483
if (source == Object.class) {
507484
return true;
508485
}
509-
if (source instanceof Class) {
510-
Class<?> sourceClass = (Class<?>) source;
511-
boolean noSuperTypes = (sourceClass.getSuperclass() == Object.class &&
512-
sourceClass.getInterfaces().length == 0);
513-
return (searchStrategy == SearchStrategy.TYPE_HIERARCHY_AND_ENCLOSING_CLASSES ? noSuperTypes &&
514-
sourceClass.getEnclosingClass() == null : noSuperTypes);
486+
if (source instanceof Class<?> sourceClass) {
487+
return (sourceClass.getSuperclass() == Object.class && sourceClass.getInterfaces().length == 0);
515488
}
516489
if (source instanceof Method sourceMethod) {
517490
return (Modifier.isPrivate(sourceMethod.getModifiers()) ||

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

+2-14
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2002-2020 the original author or authors.
2+
* Copyright 2002-2022 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -472,20 +472,8 @@ enum SearchStrategy {
472472
* superclasses and implemented interfaces. Superclass annotations do
473473
* not need to be meta-annotated with {@link Inherited @Inherited}.
474474
*/
475-
TYPE_HIERARCHY,
475+
TYPE_HIERARCHY
476476

477-
/**
478-
* Perform a full search of the entire type hierarchy on the source
479-
* <em>and</em> any enclosing classes. This strategy is similar to
480-
* {@link #TYPE_HIERARCHY} except that {@linkplain Class#getEnclosingClass()
481-
* enclosing classes} are also searched. Superclass annotations do not
482-
* need to be meta-annotated with {@link Inherited @Inherited}. When
483-
* searching a {@link Method} source, this strategy is identical to
484-
* {@link #TYPE_HIERARCHY}.
485-
* @deprecated as of Spring Framework 5.3.17; to be removed in Spring Framework 6.0
486-
*/
487-
@Deprecated
488-
TYPE_HIERARCHY_AND_ENCLOSING_CLASSES
489477
}
490478

491479
}

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

-26
Original file line numberDiff line numberDiff line change
@@ -420,32 +420,6 @@ void typeHierarchyStrategyOnMethodWithGenericParameterNonOverrideScansAnnotation
420420
assertThat(scan(source, SearchStrategy.TYPE_HIERARCHY)).containsExactly("0:TestAnnotation1");
421421
}
422422

423-
@Test
424-
@SuppressWarnings("deprecation")
425-
void typeHierarchyWithEnclosedStrategyOnEnclosedStaticClassScansAnnotations() {
426-
Class<?> source = AnnotationEnclosingClassSample.EnclosedStatic.EnclosedStaticStatic.class;
427-
assertThat(scan(source, SearchStrategy.TYPE_HIERARCHY_AND_ENCLOSING_CLASSES))
428-
.containsExactly("0:EnclosedThree", "1:EnclosedTwo", "2:EnclosedOne");
429-
}
430-
431-
@Test
432-
@SuppressWarnings("deprecation")
433-
void typeHierarchyWithEnclosedStrategyOnEnclosedInnerClassScansAnnotations() {
434-
Class<?> source = AnnotationEnclosingClassSample.EnclosedInner.EnclosedInnerInner.class;
435-
assertThat(scan(source, SearchStrategy.TYPE_HIERARCHY_AND_ENCLOSING_CLASSES))
436-
.containsExactly("0:EnclosedThree", "1:EnclosedTwo", "2:EnclosedOne");
437-
}
438-
439-
@Test
440-
@SuppressWarnings("deprecation")
441-
void typeHierarchyWithEnclosedStrategyOnMethodHierarchyUsesTypeHierarchyScan() {
442-
Method source = methodFrom(WithHierarchy.class);
443-
assertThat(scan(source, SearchStrategy.TYPE_HIERARCHY_AND_ENCLOSING_CLASSES)).containsExactly(
444-
"0:TestAnnotation1", "1:TestAnnotation5", "1:TestInheritedAnnotation5",
445-
"2:TestAnnotation6", "3:TestAnnotation2", "3:TestInheritedAnnotation2",
446-
"4:TestAnnotation3", "5:TestAnnotation4");
447-
}
448-
449423
@Test
450424
void scanWhenProcessorReturnsFromDoWithAggregateExitsEarly() {
451425
String result = AnnotationsScanner.scan(this, WithSingleSuperclass.class,

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

-16
Original file line numberDiff line numberDiff line change
@@ -710,22 +710,6 @@ void streamTypeHierarchyFromClassWithInterface() throws Exception {
710710
Transactional.class)).hasSize(1);
711711
}
712712

713-
@Test
714-
@SuppressWarnings("deprecation")
715-
void streamTypeHierarchyAndEnclosingClassesFromNonAnnotatedInnerClassWithAnnotatedEnclosingClass() {
716-
Stream<Class<?>> classes = MergedAnnotations.from(AnnotatedClass.NonAnnotatedInnerClass.class,
717-
SearchStrategy.TYPE_HIERARCHY_AND_ENCLOSING_CLASSES).stream().map(MergedAnnotation::getType);
718-
assertThat(classes).containsExactly(Component.class, Indexed.class);
719-
}
720-
721-
@Test
722-
@SuppressWarnings("deprecation")
723-
void streamTypeHierarchyAndEnclosingClassesFromNonAnnotatedStaticNestedClassWithAnnotatedEnclosingClass() {
724-
Stream<Class<?>> classes = MergedAnnotations.from(AnnotatedClass.NonAnnotatedStaticNestedClass.class,
725-
SearchStrategy.TYPE_HIERARCHY_AND_ENCLOSING_CLASSES).stream().map(MergedAnnotation::getType);
726-
assertThat(classes).containsExactly(Component.class, Indexed.class);
727-
}
728-
729713
@Test
730714
void getFromMethodWithMethodAnnotationOnLeaf() throws Exception {
731715
Method method = Leaf.class.getMethod("annotatedOnLeaf");

0 commit comments

Comments
 (0)