|
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 |
|
@@ -168,7 +169,7 @@ void typeHierarchyWhenOnClassReturnsAnnotations() {
|
168 | 169 | }
|
169 | 170 |
|
170 | 171 | @Test
|
171 |
| - void typeHierarchyWhenWhenOnSuperclassReturnsAnnotations() { |
| 172 | + void typeHierarchyWhenOnSuperclassReturnsAnnotations() { |
172 | 173 | Set<PeteRepeat> annotations = getAnnotations(null, PeteRepeat.class,
|
173 | 174 | TYPE_HIERARCHY, SubRepeatableClass.class);
|
174 | 175 | assertThat(annotations.stream().map(PeteRepeat::value)).containsExactly("A", "B", "C");
|
@@ -226,6 +227,44 @@ void typeHierarchyAnnotationsWithLocalComposedAnnotationWhoseRepeatableMetaAnnot
|
226 | 227 | assertThat(annotationTypes).containsExactly(WithRepeatedMetaAnnotations.class, Noninherited.class, Noninherited.class);
|
227 | 228 | }
|
228 | 229 |
|
| 230 | + @Test // gh-32731 |
| 231 | + void searchFindsRepeatableContainerAnnotationAndRepeatedAnnotations() { |
| 232 | + Class<?> clazz = StandardRepeatablesWithContainerWithMultipleAttributesTestCase.class; |
| 233 | + |
| 234 | + // NO RepeatableContainers |
| 235 | + MergedAnnotations mergedAnnotations = MergedAnnotations.from(clazz, TYPE_HIERARCHY, RepeatableContainers.none()); |
| 236 | + ContainerWithMultipleAttributes container = mergedAnnotations |
| 237 | + .get(ContainerWithMultipleAttributes.class) |
| 238 | + .synthesize(MergedAnnotation::isPresent).orElse(null); |
| 239 | + assertThat(container).as("container").isNotNull(); |
| 240 | + assertThat(container.name()).isEqualTo("enigma"); |
| 241 | + RepeatableWithContainerWithMultipleAttributes[] repeatedAnnotations = container.value(); |
| 242 | + assertThat(Arrays.stream(repeatedAnnotations).map(RepeatableWithContainerWithMultipleAttributes::value)) |
| 243 | + .containsExactly("A", "B"); |
| 244 | + Set<RepeatableWithContainerWithMultipleAttributes> set = |
| 245 | + mergedAnnotations.stream(RepeatableWithContainerWithMultipleAttributes.class) |
| 246 | + .collect(MergedAnnotationCollectors.toAnnotationSet()); |
| 247 | + // Only finds the locally declared repeated annotation. |
| 248 | + assertThat(set.stream().map(RepeatableWithContainerWithMultipleAttributes::value)) |
| 249 | + .containsExactly("C"); |
| 250 | + |
| 251 | + // Standard RepeatableContainers |
| 252 | + mergedAnnotations = MergedAnnotations.from(clazz, TYPE_HIERARCHY, RepeatableContainers.standardRepeatables()); |
| 253 | + container = mergedAnnotations |
| 254 | + .get(ContainerWithMultipleAttributes.class) |
| 255 | + .synthesize(MergedAnnotation::isPresent).orElse(null); |
| 256 | + assertThat(container).as("container").isNotNull(); |
| 257 | + assertThat(container.name()).isEqualTo("enigma"); |
| 258 | + repeatedAnnotations = container.value(); |
| 259 | + assertThat(Arrays.stream(repeatedAnnotations).map(RepeatableWithContainerWithMultipleAttributes::value)) |
| 260 | + .containsExactly("A", "B"); |
| 261 | + set = mergedAnnotations.stream(RepeatableWithContainerWithMultipleAttributes.class) |
| 262 | + .collect(MergedAnnotationCollectors.toAnnotationSet()); |
| 263 | + // Finds the locally declared repeated annotation plus the 2 in the container. |
| 264 | + assertThat(set.stream().map(RepeatableWithContainerWithMultipleAttributes::value)) |
| 265 | + .containsExactly("A", "B", "C"); |
| 266 | + } |
| 267 | + |
229 | 268 | private <A extends Annotation> Set<A> getAnnotations(Class<? extends Annotation> container,
|
230 | 269 | Class<A> repeatable, SearchStrategy searchStrategy, AnnotatedElement element) {
|
231 | 270 |
|
@@ -420,4 +459,27 @@ static class SubNoninheritedRepeatableClass extends NoninheritedRepeatableClass
|
420 | 459 | static class WithRepeatedMetaAnnotationsClass {
|
421 | 460 | }
|
422 | 461 |
|
| 462 | + @Retention(RetentionPolicy.RUNTIME) |
| 463 | + @interface ContainerWithMultipleAttributes { |
| 464 | + |
| 465 | + RepeatableWithContainerWithMultipleAttributes[] value(); |
| 466 | + |
| 467 | + String name() default ""; |
| 468 | + } |
| 469 | + |
| 470 | + @Retention(RetentionPolicy.RUNTIME) |
| 471 | + @Repeatable(ContainerWithMultipleAttributes.class) |
| 472 | + @interface RepeatableWithContainerWithMultipleAttributes { |
| 473 | + |
| 474 | + String value() default ""; |
| 475 | + } |
| 476 | + |
| 477 | + @ContainerWithMultipleAttributes(name = "enigma", value = { |
| 478 | + @RepeatableWithContainerWithMultipleAttributes("A"), |
| 479 | + @RepeatableWithContainerWithMultipleAttributes("B") |
| 480 | + }) |
| 481 | + @RepeatableWithContainerWithMultipleAttributes("C") |
| 482 | + static class StandardRepeatablesWithContainerWithMultipleAttributesTestCase { |
| 483 | + } |
| 484 | + |
423 | 485 | }
|
0 commit comments