From e34a5c7c258d80beec05865ea4631a0a1c2c0740 Mon Sep 17 00:00:00 2001 From: Yanming Zhou Date: Thu, 20 Feb 2025 09:31:34 +0800 Subject: [PATCH] Introduce method TestContextAnnotationUtils.getMergedAnnotation() It's equivalent to findMergedAnnotation() but return MergedAnnotation instead of synthesized annotation. Signed-off-by: Yanming Zhou --- .../context/TestContextAnnotationUtils.java | 33 +++++++++++++++++-- .../TestContextAnnotationUtilsTests.java | 31 ++++++++++++++++- 2 files changed, 61 insertions(+), 3 deletions(-) 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 65c336eaa44e..f1b980fc6ab9 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 @@ -69,6 +69,7 @@ * example, {@link ContextConfiguration#inheritLocations}. * * @author Sam Brannen + * @author Yanming Zhou * @since 5.3 * @see MergedAnnotations * @see MergedAnnotations.Search @@ -135,11 +136,39 @@ public static boolean hasAnnotation(Class clazz, Class private static @Nullable T findMergedAnnotation(Class clazz, Class annotationType, Predicate> searchEnclosingClass) { + return getMergedAnnotation(clazz, annotationType, searchEnclosingClass) + .synthesize(MergedAnnotation::isPresent).orElse(null); + } + + /** + * Get the {@link MergedAnnotation} of the specified {@code annotationType} within + * the annotation hierarchy above the supplied class. + *

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 + * 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. + * @param clazz the class to look for annotations on + * @param annotationType the type of annotation to look for + * @return a {@link MergedAnnotation} instance + * @see #findMergedAnnotation(Class, Class) + * @see #searchEnclosingClass(Class) + */ + public static MergedAnnotation getMergedAnnotation(Class clazz, Class annotationType) { + return getMergedAnnotation(clazz, annotationType, TestContextAnnotationUtils::searchEnclosingClass); + } + + private static MergedAnnotation getMergedAnnotation(Class clazz, Class annotationType, + Predicate> searchEnclosingClass) { + return MergedAnnotations.search(SearchStrategy.TYPE_HIERARCHY) .withEnclosingClasses(searchEnclosingClass) .from(clazz) - .get(annotationType) - .synthesize(MergedAnnotation::isPresent).orElse(null); + .get(annotationType); } /** diff --git a/spring-test/src/test/java/org/springframework/test/context/TestContextAnnotationUtilsTests.java b/spring-test/src/test/java/org/springframework/test/context/TestContextAnnotationUtilsTests.java index 1f105660a42a..d7e971a76455 100644 --- a/spring-test/src/test/java/org/springframework/test/context/TestContextAnnotationUtilsTests.java +++ b/spring-test/src/test/java/org/springframework/test/context/TestContextAnnotationUtilsTests.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2024 the original author or authors. + * Copyright 2002-2025 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -31,6 +31,7 @@ import org.springframework.core.SpringProperties; import org.springframework.core.annotation.AliasFor; import org.springframework.core.annotation.AnnotationUtils; +import org.springframework.core.annotation.MergedAnnotation; import org.springframework.core.annotation.Order; import org.springframework.stereotype.Component; import org.springframework.stereotype.Service; @@ -48,12 +49,40 @@ * Tests for {@link TestContextAnnotationUtils}. * * @author Sam Brannen + * @author Yanming Zhou * @since 5.3, though originally since 4.0 for the deprecated * {@link org.springframework.test.util.MetaAnnotationUtils} support * @see OverriddenMetaAnnotationAttributesTestContextAnnotationUtilsTests */ class TestContextAnnotationUtilsTests { + @Nested + @DisplayName("findMergedAnnotation() tests") + class FindMergedAnnotationTests { + + @Test + void findMergedAnnotation() { + Class startClass = MetaConfigWithDefaultAttributesTestCase.class; + Class annotationType = ContextConfiguration.class; + + ContextConfiguration annotation = TestContextAnnotationUtils.findMergedAnnotation(startClass, annotationType); + + assertThat(annotation).isNotNull(); + assertThat(annotation.classes()).containsExactlyInAnyOrder(MetaConfig.DevConfig.class, MetaConfig.ProductionConfig.class); + } + + @Test + void getMergedAnnotation() { + Class startClass = MetaConfigWithDefaultAttributesTestCase.class; + Class annotationType = ContextConfiguration.class; + + MergedAnnotation annotation = TestContextAnnotationUtils.getMergedAnnotation(startClass, annotationType); + + assertThat(annotation.isPresent()).isTrue(); + assertThat(annotation.getClassArray("classes")).containsExactlyInAnyOrder(MetaConfig.DevConfig.class, MetaConfig.ProductionConfig.class); + } + } + @Nested @DisplayName("searchEnclosingClass() tests") class SearchEnclosingClassTests {