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 0b3c20c3c9..3acb3de2d2 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 @@ -305,6 +305,13 @@ public abstract class AnnotationUtils { return annotations; } + if (annotatedElement instanceof Class) { + Class superclass = ((Class) annotatedElement).getSuperclass(); + if ((superclass != null) && (Object.class != superclass)) { + return getRepeatableAnnotations(superclass, annotationType, containerAnnotationType); + } + } + return getRepeatableAnnotations(annotatedElement, annotationType, containerAnnotationType, false); } 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 3feb22c125..8d22bc92ce 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 @@ -586,6 +586,25 @@ public class AnnotationUtilsTests { assertThat(values, is(expectedValuesSpring)); } + @Test + public void getRepeatableAnnotationsDeclaredOnMultipleSuperclasses() { + final Class clazz = SubSubMyRepeatableWithAdditionalLocalDeclarationsClass.class; + final List expectedValuesJava = Arrays.asList("X", "Y", "Z"); + final List expectedValuesSpring = Arrays.asList("X", "Y", "Z", "meta2"); + + // Java 8 + MyRepeatable[] array = clazz.getAnnotationsByType(MyRepeatable.class); + assertNotNull(array); + List values = stream(array).map(MyRepeatable::value).collect(toList()); + assertThat(values, is(expectedValuesJava)); + + // Spring + Set set = getRepeatableAnnotations(clazz, MyRepeatable.class, MyRepeatableContainer.class); + assertNotNull(set); + values = set.stream().map(MyRepeatable::value).collect(toList()); + assertThat(values, is(expectedValuesSpring)); + } + @Test public void getDeclaredRepeatableAnnotationsDeclaredOnClass() { final List expectedValuesJava = Arrays.asList("A", "B", "C"); @@ -1358,6 +1377,10 @@ public class AnnotationUtilsTests { static class SubMyRepeatableWithAdditionalLocalDeclarationsClass extends MyRepeatableClass { } + static class SubSubMyRepeatableWithAdditionalLocalDeclarationsClass extends + SubMyRepeatableWithAdditionalLocalDeclarationsClass { + } + enum RequestMethod { GET, POST }