Skip to content

Commit

Permalink
Remove TYPE_HIERARCHY_AND_ENCLOSING_CLASSES strategy for MergedAnnota…
Browse files Browse the repository at this point in the history
…tions

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
  • Loading branch information
sbrannen committed Mar 24, 2022
1 parent 1fe394f commit 42a61b9
Show file tree
Hide file tree
Showing 4 changed files with 36 additions and 59 deletions.
Expand Up @@ -107,7 +107,6 @@ private static <C, R> R processClass(C context, Class<?> source, SearchStrategy
case INHERITED_ANNOTATIONS -> processClassInheritedAnnotations(context, source, searchStrategy, processor);
case SUPERCLASS -> processClassHierarchy(context, source, processor, false, Search.never);
case TYPE_HIERARCHY -> processClassHierarchy(context, source, processor, true, searchEnclosingClass);
case TYPE_HIERARCHY_AND_ENCLOSING_CLASSES -> processClassHierarchy(context, source, processor, true, Search.always);
};
}

Expand Down Expand Up @@ -246,8 +245,7 @@ private static <C, R> R processMethod(C context, Method source,
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);
};
}
Expand Down
Expand Up @@ -356,10 +356,7 @@ static MergedAnnotations from(AnnotatedElement element, SearchStrategy searchStr
static MergedAnnotations from(AnnotatedElement element, SearchStrategy searchStrategy,
RepeatableContainers repeatableContainers, AnnotationFilter annotationFilter) {

Predicate<Class<?>> searchEnclosingClass =
(searchStrategy == SearchStrategy.TYPE_HIERARCHY_AND_ENCLOSING_CLASSES ?
Search.always : Search.never);
return from(element, searchStrategy, searchEnclosingClass, repeatableContainers, annotationFilter);
return from(element, searchStrategy, Search.never, repeatableContainers, annotationFilter);
}

private static MergedAnnotations from(AnnotatedElement element, SearchStrategy searchStrategy,
Expand Down Expand Up @@ -668,28 +665,7 @@ enum SearchStrategy {
* <p>Superclass and enclosing class annotations do not need to be
* meta-annotated with {@link Inherited @Inherited}.
*/
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
TYPE_HIERARCHY

}

Expand Down
Expand Up @@ -26,13 +26,15 @@
import java.util.Arrays;
import java.util.List;
import java.util.Objects;
import java.util.function.Predicate;
import java.util.stream.Stream;

import org.junit.jupiter.api.Test;

import org.springframework.core.annotation.MergedAnnotations.Search;
import org.springframework.core.annotation.MergedAnnotations.SearchStrategy;
import org.springframework.lang.Nullable;
import org.springframework.util.ClassUtils;
import org.springframework.util.ReflectionUtils;

import static org.assertj.core.api.Assertions.assertThat;
Expand Down Expand Up @@ -422,29 +424,34 @@ void typeHierarchyStrategyOnMethodWithGenericParameterNonOverrideScansAnnotation
}

@Test
@SuppressWarnings("deprecation")
void typeHierarchyWithEnclosedStrategyOnEnclosedStaticClassScansAnnotations() {
void typeHierarchyStrategyWithEnclosingClassPredicatesOnEnclosedStaticClassScansAnnotations() {
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");
}

@Test
@SuppressWarnings("deprecation")
void typeHierarchyWithEnclosedStrategyOnEnclosedInnerClassScansAnnotations() {
void typeHierarchyStrategyWithEnclosingClassPredicatesOnEnclosedInnerClassScansAnnotations() {
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");
}

@Test
@SuppressWarnings("deprecation")
void typeHierarchyWithEnclosedStrategyOnMethodHierarchyUsesTypeHierarchyScan() {
void typeHierarchyStrategyWithEnclosingClassPredicatesOnMethodHierarchyUsesTypeHierarchyScan() {
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");
assertThat(scan(source, SearchStrategy.TYPE_HIERARCHY, Search.always).toList())
.isEqualTo(scan(source, SearchStrategy.TYPE_HIERARCHY, ClassUtils::isInnerClass).toList())
.containsExactly(
"0:TestAnnotation1", "1:TestAnnotation5", "1:TestInheritedAnnotation5",
"2:TestAnnotation6", "3:TestAnnotation2", "3:TestInheritedAnnotation2",
"4:TestAnnotation3", "5:TestAnnotation4");
}

@Test
Expand Down Expand Up @@ -509,8 +516,14 @@ private Method methodFrom(Class<?> type) {
}

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<>();
scan(this, element, searchStrategy,
scan(this, element, searchStrategy, searchEnclosingClass,
(criteria, aggregateIndex, source, annotations) -> {
trackIndexedAnnotations(aggregateIndex, annotations, results);
return null; // continue searching
Expand All @@ -521,7 +534,13 @@ private Stream<String> scan(AnnotatedElement element, SearchStrategy searchStrat
private static <C, R> R scan(C context, AnnotatedElement source, SearchStrategy searchStrategy,
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) {
Expand Down
Expand Up @@ -843,22 +843,6 @@ void streamTypeHierarchyFromClassWithInterface() throws Exception {
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
@SuppressWarnings("deprecation")
void getFromMethodWithMethodAnnotationOnLeaf() throws Exception {
Expand Down

0 comments on commit 42a61b9

Please sign in to comment.