diff --git a/spring-core/src/main/java/org/springframework/core/annotation/AnnotationUtils.java b/spring-core/src/main/java/org/springframework/core/annotation/AnnotationUtils.java index 0351c6d01b..82617e121c 100644 --- a/spring-core/src/main/java/org/springframework/core/annotation/AnnotationUtils.java +++ b/spring-core/src/main/java/org/springframework/core/annotation/AnnotationUtils.java @@ -197,7 +197,8 @@ public abstract class AnnotationUtils { return null; } // Exhaustive retrieval of merged annotations... - return MergedAnnotations.from(annotation) + return MergedAnnotations.from(null, new Annotation[] {annotation}, + RepeatableContainers.none(), AnnotationFilter.PLAIN) .get(annotationType).withNonMergedAttributes() .synthesize(AnnotationUtils::isSingleLevelPresent).orElse(null); } @@ -492,7 +493,8 @@ public abstract class AnnotationUtils { return annotatedElement.getDeclaredAnnotation(annotationType); } // Exhaustive retrieval of merged annotations... - return MergedAnnotations.from(annotatedElement, SearchStrategy.INHERITED_ANNOTATIONS) + return MergedAnnotations.from(annotatedElement, SearchStrategy.INHERITED_ANNOTATIONS, + RepeatableContainers.none(), AnnotationFilter.PLAIN) .get(annotationType).withNonMergedAttributes() .synthesize(MergedAnnotation::isPresent).orElse(null); } @@ -523,7 +525,8 @@ public abstract class AnnotationUtils { return method.getDeclaredAnnotation(annotationType); } // Exhaustive retrieval of merged annotations... - return MergedAnnotations.from(method, SearchStrategy.EXHAUSTIVE) + return MergedAnnotations.from(method, SearchStrategy.EXHAUSTIVE, + RepeatableContainers.none(), AnnotationFilter.PLAIN) .get(annotationType).withNonMergedAttributes() .synthesize(MergedAnnotation::isPresent).orElse(null); } @@ -561,7 +564,8 @@ public abstract class AnnotationUtils { return clazz.getDeclaredAnnotation(annotationType); } // Exhaustive retrieval of merged annotations... - return MergedAnnotations.from(clazz, SearchStrategy.EXHAUSTIVE) + return MergedAnnotations.from(clazz, SearchStrategy.EXHAUSTIVE, + RepeatableContainers.none(), AnnotationFilter.PLAIN) .get(annotationType).withNonMergedAttributes() .synthesize(MergedAnnotation::isPresent).orElse(null); } diff --git a/spring-core/src/test/java/org/springframework/core/annotation/AnnotationUtilsTests.java b/spring-core/src/test/java/org/springframework/core/annotation/AnnotationUtilsTests.java index a6a1616ec6..7b4faea5c1 100644 --- a/spring-core/src/test/java/org/springframework/core/annotation/AnnotationUtilsTests.java +++ b/spring-core/src/test/java/org/springframework/core/annotation/AnnotationUtilsTests.java @@ -979,6 +979,13 @@ public class AnnotationUtilsTests { assertEquals("value from synthesized component: ", "webController", synthesizedComponent.value()); } + @Test // gh-22702 + public void findAnnotationWithRepeatablesElements() { + assertNull(AnnotationUtils.findAnnotation(TestRepeatablesClass.class, + TestRepeatable.class)); + assertNotNull(AnnotationUtils.findAnnotation(TestRepeatablesClass.class, + TestRepeatableContainer.class)); + } @SafeVarargs static T[] asArray(T... arr) { @@ -1808,4 +1815,21 @@ public class AnnotationUtilsTests { interface ContextConfigMismatch { } + @Retention(RetentionPolicy.RUNTIME) + @Repeatable(TestRepeatableContainer.class) + static @interface TestRepeatable { + + String value(); + } + + @Retention(RetentionPolicy.RUNTIME) + static @interface TestRepeatableContainer { + + TestRepeatable[] value(); + } + + @TestRepeatable("a") + @TestRepeatable("b") + static class TestRepeatablesClass { + } }