|
24 | 24 | import java.lang.annotation.RetentionPolicy;
|
25 | 25 | import java.lang.annotation.Target;
|
26 | 26 | import java.lang.reflect.AnnotatedElement;
|
| 27 | +import java.util.Arrays; |
27 | 28 | import java.util.Set;
|
28 | 29 | import java.util.stream.Stream;
|
29 | 30 |
|
@@ -175,7 +176,7 @@ void typeHierarchyWhenOnClassReturnsAnnotations() {
|
175 | 176 | }
|
176 | 177 |
|
177 | 178 | @Test
|
178 |
| - void typeHierarchyWhenWhenOnSuperclassReturnsAnnotations() { |
| 179 | + void typeHierarchyWhenOnSuperclassReturnsAnnotations() { |
179 | 180 | Set<PeteRepeat> annotations = getAnnotations(null, PeteRepeat.class,
|
180 | 181 | SearchStrategy.TYPE_HIERARCHY, SubRepeatableClass.class);
|
181 | 182 | assertThat(annotations.stream().map(PeteRepeat::value)).containsExactly("A", "B",
|
@@ -240,6 +241,44 @@ void typeHierarchyAnnotationsWithLocalComposedAnnotationWhoseRepeatableMetaAnnot
|
240 | 241 | assertThat(annotationTypes).containsExactly(WithRepeatedMetaAnnotations.class, Noninherited.class, Noninherited.class);
|
241 | 242 | }
|
242 | 243 |
|
| 244 | + @Test // gh-32731 |
| 245 | + void searchFindsRepeatableContainerAnnotationAndRepeatedAnnotations() { |
| 246 | + Class<?> clazz = StandardRepeatablesWithContainerWithMultipleAttributesTestCase.class; |
| 247 | + |
| 248 | + // NO RepeatableContainers |
| 249 | + MergedAnnotations mergedAnnotations = MergedAnnotations.from(clazz, TYPE_HIERARCHY, RepeatableContainers.none()); |
| 250 | + ContainerWithMultipleAttributes container = mergedAnnotations |
| 251 | + .get(ContainerWithMultipleAttributes.class) |
| 252 | + .synthesize(MergedAnnotation::isPresent).orElse(null); |
| 253 | + assertThat(container).as("container").isNotNull(); |
| 254 | + assertThat(container.name()).isEqualTo("enigma"); |
| 255 | + RepeatableWithContainerWithMultipleAttributes[] repeatedAnnotations = container.value(); |
| 256 | + assertThat(Arrays.stream(repeatedAnnotations).map(RepeatableWithContainerWithMultipleAttributes::value)) |
| 257 | + .containsExactly("A", "B"); |
| 258 | + Set<RepeatableWithContainerWithMultipleAttributes> set = |
| 259 | + mergedAnnotations.stream(RepeatableWithContainerWithMultipleAttributes.class) |
| 260 | + .collect(MergedAnnotationCollectors.toAnnotationSet()); |
| 261 | + // Only finds the locally declared repeated annotation. |
| 262 | + assertThat(set.stream().map(RepeatableWithContainerWithMultipleAttributes::value)) |
| 263 | + .containsExactly("C"); |
| 264 | + |
| 265 | + // Standard RepeatableContainers |
| 266 | + mergedAnnotations = MergedAnnotations.from(clazz, TYPE_HIERARCHY, RepeatableContainers.standardRepeatables()); |
| 267 | + container = mergedAnnotations |
| 268 | + .get(ContainerWithMultipleAttributes.class) |
| 269 | + .synthesize(MergedAnnotation::isPresent).orElse(null); |
| 270 | + assertThat(container).as("container").isNotNull(); |
| 271 | + assertThat(container.name()).isEqualTo("enigma"); |
| 272 | + repeatedAnnotations = container.value(); |
| 273 | + assertThat(Arrays.stream(repeatedAnnotations).map(RepeatableWithContainerWithMultipleAttributes::value)) |
| 274 | + .containsExactly("A", "B"); |
| 275 | + set = mergedAnnotations.stream(RepeatableWithContainerWithMultipleAttributes.class) |
| 276 | + .collect(MergedAnnotationCollectors.toAnnotationSet()); |
| 277 | + // Finds the locally declared repeated annotation plus the 2 in the container. |
| 278 | + assertThat(set.stream().map(RepeatableWithContainerWithMultipleAttributes::value)) |
| 279 | + .containsExactly("A", "B", "C"); |
| 280 | + } |
| 281 | + |
243 | 282 | private <A extends Annotation> Set<A> getAnnotations(Class<? extends Annotation> container,
|
244 | 283 | Class<A> repeatable, SearchStrategy searchStrategy, AnnotatedElement element) {
|
245 | 284 |
|
@@ -449,4 +488,27 @@ static class SubNoninheritedRepeatableClass extends NoninheritedRepeatableClass
|
449 | 488 | static class WithRepeatedMetaAnnotationsClass {
|
450 | 489 | }
|
451 | 490 |
|
| 491 | + @Retention(RetentionPolicy.RUNTIME) |
| 492 | + @interface ContainerWithMultipleAttributes { |
| 493 | + |
| 494 | + RepeatableWithContainerWithMultipleAttributes[] value(); |
| 495 | + |
| 496 | + String name() default ""; |
| 497 | + } |
| 498 | + |
| 499 | + @Retention(RetentionPolicy.RUNTIME) |
| 500 | + @Repeatable(ContainerWithMultipleAttributes.class) |
| 501 | + @interface RepeatableWithContainerWithMultipleAttributes { |
| 502 | + |
| 503 | + String value() default ""; |
| 504 | + } |
| 505 | + |
| 506 | + @ContainerWithMultipleAttributes(name = "enigma", value = { |
| 507 | + @RepeatableWithContainerWithMultipleAttributes("A"), |
| 508 | + @RepeatableWithContainerWithMultipleAttributes("B") |
| 509 | + }) |
| 510 | + @RepeatableWithContainerWithMultipleAttributes("C") |
| 511 | + static class StandardRepeatablesWithContainerWithMultipleAttributesTestCase { |
| 512 | + } |
| 513 | + |
452 | 514 | }
|
0 commit comments