diff --git a/spring-test/src/main/java/org/springframework/test/context/TestContextAnnotationUtils.java b/spring-test/src/main/java/org/springframework/test/context/TestContextAnnotationUtils.java index e8fa944d48d..f4289f4cd16 100644 --- a/spring-test/src/main/java/org/springframework/test/context/TestContextAnnotationUtils.java +++ b/spring-test/src/main/java/org/springframework/test/context/TestContextAnnotationUtils.java @@ -43,7 +43,8 @@ import org.springframework.util.ObjectUtils; /** * {@code TestContextAnnotationUtils} is a collection of utility methods that * complements the standard support already available in {@link AnnotationUtils} - * and {@link AnnotatedElementUtils}. + * and {@link AnnotatedElementUtils}, while transparently honoring + * {@link NestedTestConfiguration @NestedTestConfiguration} semantics. * *
Mainly for internal use within the Spring TestContext Framework. * @@ -56,8 +57,8 @@ import org.springframework.util.ObjectUtils; * *
The additional information provided by an {@code AnnotationDescriptor} is * required by the Spring TestContext Framework in order to be able to - * support class hierarchy traversals for annotations such as - * {@link ContextConfiguration @ContextConfiguration}, + * support class inheritance and enclosing class hierarchy traversals for + * annotations such as {@link ContextConfiguration @ContextConfiguration}, * {@link TestExecutionListeners @TestExecutionListeners}, and * {@link ActiveProfiles @ActiveProfiles} which offer support for merging and * overriding various inherited annotation attributes — for @@ -84,8 +85,9 @@ public abstract class TestContextAnnotationUtils { *
In the context of this method, the term "above" means within the * {@linkplain Class#getSuperclass() superclass} hierarchy or within the * {@linkplain Class#getEnclosingClass() enclosing class} hierarchy of the - * supplied class. The enclosing class hierarchy will only be searched if - * appropriate. + * supplied class. The enclosing class hierarchy will only be searched + * according to {@link NestedTestConfiguration @NestedTestConfiguration} + * semantics. *
{@link org.springframework.core.annotation.AliasFor @AliasFor} semantics * are fully supported, both within a single annotation and within annotation * hierarchies. @@ -121,8 +123,9 @@ public abstract class TestContextAnnotationUtils { * any local declarations of the repeatable annotation. If no inherited * annotations are found, this method will search within the * {@linkplain Class#getEnclosingClass() enclosing class} hierarchy of the - * supplied class. The enclosing class hierarchy will only be searched if - * appropriate. + * supplied class. The enclosing class hierarchy will only be searched + * according to {@link NestedTestConfiguration @NestedTestConfiguration} + * semantics. *
The container type that holds the repeatable annotations will be looked up * via {@link java.lang.annotation.Repeatable}. *
{@link org.springframework.core.annotation.AliasFor @AliasFor} semantics @@ -158,8 +161,9 @@ public abstract class TestContextAnnotationUtils { /** * Find the {@link AnnotationDescriptor} for the supplied {@code annotationType} - * on the supplied {@link Class}, traversing its annotations, interfaces, and - * superclasses if no annotation can be found on the given class itself. + * on the supplied {@link Class}, traversing its annotations, interfaces, + * superclasses, and enclosing classes if no annotation can be found on the + * given class itself. *
This method explicitly handles class-level annotations which are not * declared as {@linkplain java.lang.annotation.Inherited inherited} as * well as meta-annotations. @@ -167,13 +171,17 @@ public abstract class TestContextAnnotationUtils { *
In this context, the term recursively means that the search * process continues by returning to step #1 with the current annotation, - * interface, or superclass as the class to look for annotations on. + * interface, superclass, or enclosing class as the class to look for + * annotations on. * @param clazz the class to look for annotations on * @param annotationType the type of annotation to look for * @return the corresponding annotation descriptor if the annotation was found; @@ -194,6 +202,8 @@ public abstract class TestContextAnnotationUtils { * visited. * @param clazz the class to look for annotations on * @param annotationType the type of annotation to look for + * @param searchEnclosingClass a predicate which evaluates to {@code true} + * if a search should be performed on the enclosing class * @param visited the set of annotations that have already been visited * @return the corresponding annotation descriptor if the annotation was found; * otherwise {@code null} @@ -258,24 +268,28 @@ public abstract class TestContextAnnotationUtils { * in the inheritance hierarchy of the specified {@code clazz} (including * the specified {@code clazz} itself) which declares at least one of the * specified {@code annotationTypes}. - *
This method traverses the annotations, interfaces, and superclasses - * of the specified {@code clazz} if no annotation can be found on the given - * class itself. + *
This method traverses the annotations, interfaces, superclasses, and + * enclosing classes of the specified {@code clazz} if no annotation can be + * found on the given class itself. *
This method explicitly handles class-level annotations which are not * declared as {@linkplain java.lang.annotation.Inherited inherited} as * well as meta-annotations. *
The algorithm operates as follows: *
In this context, the term recursively means that the search
* process continues by returning to step #1 with the current annotation,
- * interface, or superclass as the class to look for annotations on.
+ * interface, superclass, or enclosing class as the class to look for
+ * annotations on.
* @param clazz the class to look for annotations on
* @param annotationTypes the types of annotations to look for
* @return the corresponding annotation descriptor if one of the annotations
@@ -287,6 +301,7 @@ public abstract class TestContextAnnotationUtils {
public static UntypedAnnotationDescriptor findAnnotationDescriptorForTypes(
Class> clazz, Class extends Annotation>... annotationTypes) {
+ assertNonEmptyAnnotationTypeArray(annotationTypes, "The list of annotation types must not be empty");
return findAnnotationDescriptorForTypes(clazz, annotationTypes, new HashSet<>());
}
@@ -304,7 +319,6 @@ public abstract class TestContextAnnotationUtils {
private static UntypedAnnotationDescriptor findAnnotationDescriptorForTypes(@Nullable Class> clazz,
Class extends Annotation>[] annotationTypes, Set