diff --git a/spring-core/src/main/java/org/springframework/core/annotation/AnnotatedElementUtils.java b/spring-core/src/main/java/org/springframework/core/annotation/AnnotatedElementUtils.java index 35ed4562a6..f48bb77a93 100644 --- a/spring-core/src/main/java/org/springframework/core/annotation/AnnotatedElementUtils.java +++ b/spring-core/src/main/java/org/springframework/core/annotation/AnnotatedElementUtils.java @@ -443,13 +443,17 @@ public abstract class AnnotatedElementUtils { * support such a use case, favor {@link #getMergedRepeatableAnnotations(AnnotatedElement, Class)} * over this method or alternatively use the {@link MergedAnnotations} API * directly in conjunction with {@link RepeatableContainers} that are - * {@linkplain RepeatableContainers#and(Class, Class) composed} to support - * multiple repeatable annotation types. + * {@linkplain RepeatableContainers#plus(Class, Class) composed} to support + * multiple repeatable annotation types — for example: + *
+	 * RepeatableContainers.standardRepeatables()
+	 *     .plus(MyRepeatable1.class, MyContainer1.class)
+	 *     .plus(MyRepeatable2.class, MyContainer2.class);
* @param element the annotated element (never {@code null}) - * @param annotationType the annotation type to find (never {@code null}) - * @param containerType the type of the container that holds the annotations; - * may be {@code null} if the container type should be looked up via - * {@link java.lang.annotation.Repeatable} + * @param annotationType the repeatable annotation type to find (never {@code null}) + * @param containerType the type of the container that holds the repeatable + * annotations; may be {@code null} if the container type should be looked up + * via {@link java.lang.annotation.Repeatable @Repeatable} * @return the set of all merged repeatable {@code Annotations} found, * or an empty set if none were found * @throws IllegalArgumentException if the {@code element} or {@code annotationType} @@ -740,13 +744,17 @@ public abstract class AnnotatedElementUtils { * support such a use case, favor {@link #findMergedRepeatableAnnotations(AnnotatedElement, Class)} * over this method or alternatively use the {@link MergedAnnotations} API * directly in conjunction with {@link RepeatableContainers} that are - * {@linkplain RepeatableContainers#and(Class, Class) composed} to support - * multiple repeatable annotation types. + * {@linkplain RepeatableContainers#plus(Class, Class) composed} to support + * multiple repeatable annotation types — for example: + *
+	 * RepeatableContainers.standardRepeatables()
+	 *     .plus(MyRepeatable1.class, MyContainer1.class)
+	 *     .plus(MyRepeatable2.class, MyContainer2.class);
* @param element the annotated element (never {@code null}) - * @param annotationType the annotation type to find (never {@code null}) - * @param containerType the type of the container that holds the annotations; - * may be {@code null} if the container type should be looked up via - * {@link java.lang.annotation.Repeatable} + * @param annotationType the repeatable annotation type to find (never {@code null}) + * @param containerType the type of the container that holds the repeatable + * annotations; may be {@code null} if the container type should be looked up + * via {@link java.lang.annotation.Repeatable @Repeatable} * @return the set of all merged repeatable {@code Annotations} found, * or an empty set if none were found * @throws IllegalArgumentException if the {@code element} or {@code annotationType} @@ -775,7 +783,7 @@ public abstract class AnnotatedElementUtils { RepeatableContainers repeatableContainers; if (containerType == null) { - // Invoke RepeatableContainers.of() in order to adhere to the contract of + // Invoke RepeatableContainers.explicitRepeatable() in order to adhere to the contract of // getMergedRepeatableAnnotations() which states that an IllegalArgumentException // will be thrown if the container cannot be resolved. // @@ -784,11 +792,11 @@ public abstract class AnnotatedElementUtils { // annotation types). // // See https://github.com/spring-projects/spring-framework/issues/20279 - RepeatableContainers.of(annotationType, null); + RepeatableContainers.explicitRepeatable(annotationType, null); repeatableContainers = RepeatableContainers.standardRepeatables(); } else { - repeatableContainers = RepeatableContainers.of(annotationType, containerType); + repeatableContainers = RepeatableContainers.explicitRepeatable(annotationType, containerType); } return MergedAnnotations.from(element, SearchStrategy.INHERITED_ANNOTATIONS, repeatableContainers); } @@ -802,7 +810,7 @@ public abstract class AnnotatedElementUtils { RepeatableContainers repeatableContainers; if (containerType == null) { - // Invoke RepeatableContainers.of() in order to adhere to the contract of + // Invoke RepeatableContainers.explicitRepeatable() in order to adhere to the contract of // findMergedRepeatableAnnotations() which states that an IllegalArgumentException // will be thrown if the container cannot be resolved. // @@ -811,11 +819,11 @@ public abstract class AnnotatedElementUtils { // annotation types). // // See https://github.com/spring-projects/spring-framework/issues/20279 - RepeatableContainers.of(annotationType, null); + RepeatableContainers.explicitRepeatable(annotationType, null); repeatableContainers = RepeatableContainers.standardRepeatables(); } else { - repeatableContainers = RepeatableContainers.of(annotationType, containerType); + repeatableContainers = RepeatableContainers.explicitRepeatable(annotationType, containerType); } return MergedAnnotations.from(element, SearchStrategy.TYPE_HIERARCHY, repeatableContainers); } 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 fe46a92076..862cadbf0e 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 @@ -370,7 +370,7 @@ public abstract class AnnotationUtils { Class annotationType, @Nullable Class containerAnnotationType) { RepeatableContainers repeatableContainers = (containerAnnotationType != null ? - RepeatableContainers.of(annotationType, containerAnnotationType) : + RepeatableContainers.explicitRepeatable(annotationType, containerAnnotationType) : RepeatableContainers.standardRepeatables()); return MergedAnnotations.from(annotatedElement, SearchStrategy.SUPERCLASS, repeatableContainers) @@ -451,7 +451,7 @@ public abstract class AnnotationUtils { Class annotationType, @Nullable Class containerAnnotationType) { RepeatableContainers repeatableContainers = containerAnnotationType != null ? - RepeatableContainers.of(annotationType, containerAnnotationType) : + RepeatableContainers.explicitRepeatable(annotationType, containerAnnotationType) : RepeatableContainers.standardRepeatables(); return MergedAnnotations.from(annotatedElement, SearchStrategy.DIRECT, repeatableContainers) diff --git a/spring-core/src/main/java/org/springframework/core/annotation/RepeatableContainers.java b/spring-core/src/main/java/org/springframework/core/annotation/RepeatableContainers.java index ee4cd54d89..82717917b2 100644 --- a/spring-core/src/main/java/org/springframework/core/annotation/RepeatableContainers.java +++ b/spring-core/src/main/java/org/springframework/core/annotation/RepeatableContainers.java @@ -30,15 +30,38 @@ import org.springframework.util.ConcurrentReferenceHashMap; import org.springframework.util.ObjectUtils; /** - * Strategy used to determine annotations that act as containers for other - * annotations. The {@link #standardRepeatables()} method provides a default - * strategy that respects Java's {@link Repeatable @Repeatable} support and - * should be suitable for most situations. + * Strategy used to find repeatable annotations within container annotations. * - *

The {@link #of} method can be used to register relationships for - * annotations that do not wish to use {@link Repeatable @Repeatable}. + *

{@link #standardRepeatables() RepeatableContainers.standardRepeatables()} + * provides a default strategy that respects Java's {@link Repeatable @Repeatable} + * support and is suitable for most situations. * - *

To completely disable repeatable support use {@link #none()}. + *

If you need to register repeatable annotation types that do not make use of + * {@code @Repeatable}, you should typically use {@code standardRepeatables()} + * combined with {@link #plus(Class, Class)}. Note that multiple invocations of + * {@code plus()} can be chained together to register multiple repeatable/container + * type pairs. For example: + * + *

+ * RepeatableContainers repeatableContainers =
+ *     RepeatableContainers.standardRepeatables()
+ *         .plus(MyRepeatable1.class, MyContainer1.class)
+ *         .plus(MyRepeatable2.class, MyContainer2.class);
+ * + *

For special use cases where you are certain that you do not need Java's + * {@code @Repeatable} support, you can use {@link #explicitRepeatable(Class, Class) + * RepeatableContainers.explicitRepeatable()} to create an instance of + * {@code RepeatableContainers} that only supports explicit repeatable/container + * type pairs. As with {@code standardRepeatables()}, {@code plus()} can be used + * to register additional repeatable/container type pairs. For example: + * + *

+ * RepeatableContainers repeatableContainers =
+ *     RepeatableContainers.explicitRepeatable(MyRepeatable1.class, MyContainer1.class)
+ *         .plus(MyRepeatable2.class, MyContainer2.class);
+ * + *

To completely disable repeatable annotation support use + * {@link #none() RepeatableContainers.none()}. * * @author Phillip Webb * @author Sam Brannen @@ -55,22 +78,46 @@ public abstract class RepeatableContainers { this.parent = parent; } - /** - * Add an additional explicit relationship between a container and - * repeatable annotation. - *

WARNING: the arguments supplied to this method are in the reverse order - * of those supplied to {@link #of(Class, Class)}. - * @param container the container annotation type + * Register a pair of repeatable and container annotation types. + *

See the {@linkplain RepeatableContainers class-level javadoc} for examples. * @param repeatable the repeatable annotation type - * @return a new {@link RepeatableContainers} instance + * @param container the container annotation type + * @return a new {@code RepeatableContainers} instance that is chained to + * the current instance + * @since 7.0 */ - public RepeatableContainers and(Class container, - Class repeatable) { + public final RepeatableContainers plus(Class repeatable, + Class container) { return new ExplicitRepeatableContainer(this, repeatable, container); } + /** + * Register a pair of container and repeatable annotation types. + *

WARNING: The arguments supplied to this method are in + * the reverse order of those supplied to {@link #plus(Class, Class)}, + * {@link #explicitRepeatable(Class, Class)}, and {@link #of(Class, Class)}. + * @param container the container annotation type + * @param repeatable the repeatable annotation type + * @return a new {@code RepeatableContainers} instance that is chained to + * the current instance + * @deprecated as of Spring Framework 7.0, in favor of {@link #plus(Class, Class)} + */ + @Deprecated(since = "7.0") + public RepeatableContainers and(Class container, + Class repeatable) { + + return plus(repeatable, container); + } + + /** + * Find repeated annotations contained in the supplied {@code annotation}. + * @param annotation the candidate container annotation + * @return the repeated annotations found in the supplied container annotation + * (potentially an empty array), or {@code null} if the supplied annotation is + * not a supported container annotation + */ Annotation @Nullable [] findRepeatedAnnotations(Annotation annotation) { if (this.parent == null) { return null; @@ -98,41 +145,92 @@ public abstract class RepeatableContainers { /** - * Create a {@link RepeatableContainers} instance that searches using Java's - * {@link Repeatable @Repeatable} annotation. - * @return a {@link RepeatableContainers} instance + * Create a {@link RepeatableContainers} instance that searches for repeated + * annotations according to the semantics of Java's {@link Repeatable @Repeatable} + * annotation. + *

See the {@linkplain RepeatableContainers class-level javadoc} for examples. + * @return a {@code RepeatableContainers} instance that supports {@code @Repeatable} + * @see #plus(Class, Class) */ public static RepeatableContainers standardRepeatables() { return StandardRepeatableContainers.INSTANCE; } /** - * Create a {@link RepeatableContainers} instance that uses predefined - * repeatable and container types. - *

WARNING: the arguments supplied to this method are in the reverse order - * of those supplied to {@link #and(Class, Class)}. + * Create a {@link RepeatableContainers} instance that searches for repeated + * annotations by taking into account the supplied repeatable and container + * annotation types. + *

WARNING: The {@code RepeatableContainers} instance + * returned by this factory method does not respect Java's + * {@link Repeatable @Repeatable} support. Use {@link #standardRepeatables()} + * for standard {@code @Repeatable} support, optionally combined with + * {@link #plus(Class, Class)}. + *

If the supplied container annotation type is not {@code null}, it must + * declare a {@code value} attribute returning an array of repeatable + * annotations. If the supplied container annotation type is {@code null}, the + * container will be deduced by inspecting the {@code @Repeatable} annotation + * on the {@code repeatable} annotation type. + *

See the {@linkplain RepeatableContainers class-level javadoc} for examples. * @param repeatable the repeatable annotation type - * @param container the container annotation type or {@code null}. If specified, - * this annotation must declare a {@code value} attribute returning an array - * of repeatable annotations. If not specified, the container will be - * deduced by inspecting the {@code @Repeatable} annotation on - * {@code repeatable}. - * @return a {@link RepeatableContainers} instance + * @param container the container annotation type or {@code null} + * @return a {@code RepeatableContainers} instance that does not support + * {@link Repeatable @Repeatable} * @throws IllegalArgumentException if the supplied container type is * {@code null} and the annotation type is not a repeatable annotation * @throws AnnotationConfigurationException if the supplied container type * is not a properly configured container for a repeatable annotation + * @since 7.0 + * @see #standardRepeatables() + * @see #plus(Class, Class) */ - public static RepeatableContainers of( + public static RepeatableContainers explicitRepeatable( Class repeatable, @Nullable Class container) { return new ExplicitRepeatableContainer(null, repeatable, container); } + /** + * Create a {@link RepeatableContainers} instance that searches for repeated + * annotations by taking into account the supplied repeatable and container + * annotation types. + *

WARNING: The {@code RepeatableContainers} instance + * returned by this factory method does not respect Java's + * {@link Repeatable @Repeatable} support. Use {@link #standardRepeatables()} + * for standard {@code @Repeatable} support, optionally combined with + * {@link #plus(Class, Class)}. + *

WARNING: The arguments supplied to this method are in + * the reverse order of those supplied to {@link #and(Class, Class)}. + *

If the supplied container annotation type is not {@code null}, it must + * declare a {@code value} attribute returning an array of repeatable + * annotations. If the supplied container annotation type is {@code null}, the + * container will be deduced by inspecting the {@code @Repeatable} annotation + * on the {@code repeatable} annotation type. + * @param repeatable the repeatable annotation type + * @param container the container annotation type or {@code null} + * @return a {@code RepeatableContainers} instance that does not support + * {@link Repeatable @Repeatable} + * @throws IllegalArgumentException if the supplied container type is + * {@code null} and the annotation type is not a repeatable annotation + * @throws AnnotationConfigurationException if the supplied container type + * is not a properly configured container for a repeatable annotation + * @deprecated as of Spring Framework 7.0, in favor of {@link #explicitRepeatable(Class, Class)} + */ + @Deprecated(since = "7.0") + public static RepeatableContainers of( + Class repeatable, @Nullable Class container) { + + return explicitRepeatable(repeatable, container); + } + /** * Create a {@link RepeatableContainers} instance that does not support any * repeatable annotations. - * @return a {@link RepeatableContainers} instance + *

Note, however, that {@link #plus(Class, Class)} may still be invoked on + * the {@code RepeatableContainers} instance returned from this method. + *

See the {@linkplain RepeatableContainers class-level javadoc} for examples + * and further details. + * @return a {@code RepeatableContainers} instance that does not support + * repeatable annotations */ public static RepeatableContainers none() { return NoRepeatableContainers.INSTANCE; diff --git a/spring-core/src/test/java/org/springframework/core/annotation/MergedAnnotationsRepeatableAnnotationTests.java b/spring-core/src/test/java/org/springframework/core/annotation/MergedAnnotationsRepeatableAnnotationTests.java index 404073b9b4..a734c51a47 100644 --- a/spring-core/src/test/java/org/springframework/core/annotation/MergedAnnotationsRepeatableAnnotationTests.java +++ b/spring-core/src/test/java/org/springframework/core/annotation/MergedAnnotationsRepeatableAnnotationTests.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. @@ -274,7 +274,7 @@ class MergedAnnotationsRepeatableAnnotationTests { private Set getAnnotations(Class container, Class repeatable, SearchStrategy searchStrategy, AnnotatedElement element, AnnotationFilter annotationFilter) { - RepeatableContainers containers = RepeatableContainers.of(repeatable, container); + RepeatableContainers containers = RepeatableContainers.explicitRepeatable(repeatable, container); MergedAnnotations annotations = MergedAnnotations.from(element, searchStrategy, containers, annotationFilter); return annotations.stream(repeatable).collect(MergedAnnotationCollectors.toAnnotationSet()); } diff --git a/spring-core/src/test/java/org/springframework/core/annotation/MergedAnnotationsTests.java b/spring-core/src/test/java/org/springframework/core/annotation/MergedAnnotationsTests.java index 30559d8bdf..65022cb36b 100644 --- a/spring-core/src/test/java/org/springframework/core/annotation/MergedAnnotationsTests.java +++ b/spring-core/src/test/java/org/springframework/core/annotation/MergedAnnotationsTests.java @@ -136,7 +136,7 @@ class MergedAnnotationsTests { @Test void searchFromClassWithCustomRepeatableContainers() { assertThat(MergedAnnotations.from(HierarchyClass.class).stream(TestConfiguration.class)).isEmpty(); - RepeatableContainers containers = RepeatableContainers.of(TestConfiguration.class, Hierarchy.class); + RepeatableContainers containers = RepeatableContainers.explicitRepeatable(TestConfiguration.class, Hierarchy.class); MergedAnnotations annotations = MergedAnnotations.search(SearchStrategy.DIRECT) .withRepeatableContainers(containers) @@ -1364,7 +1364,7 @@ class MergedAnnotationsTests { @SuppressWarnings("deprecation") void streamRepeatableDeclaredOnClassWithAttributeAliases() { assertThat(MergedAnnotations.from(HierarchyClass.class).stream(TestConfiguration.class)).isEmpty(); - RepeatableContainers containers = RepeatableContainers.of(TestConfiguration.class, Hierarchy.class); + RepeatableContainers containers = RepeatableContainers.explicitRepeatable(TestConfiguration.class, Hierarchy.class); MergedAnnotations annotations = MergedAnnotations.from(HierarchyClass.class, SearchStrategy.DIRECT, containers, AnnotationFilter.NONE); assertThat(annotations.stream(TestConfiguration.class) @@ -1440,7 +1440,7 @@ class MergedAnnotationsTests { private void testExplicitRepeatables(SearchStrategy searchStrategy, Class element, String[] expected) { MergedAnnotations annotations = MergedAnnotations.from(element, searchStrategy, - RepeatableContainers.of(MyRepeatable.class, MyRepeatableContainer.class)); + RepeatableContainers.explicitRepeatable(MyRepeatable.class, MyRepeatableContainer.class)); Stream values = annotations.stream(MyRepeatable.class) .filter(MergedAnnotationPredicates.firstRunOf(MergedAnnotation::getAggregateIndex)) .map(annotation -> annotation.getString("value")); diff --git a/spring-core/src/test/java/org/springframework/core/annotation/NestedRepeatableAnnotationsTests.java b/spring-core/src/test/java/org/springframework/core/annotation/NestedRepeatableAnnotationsTests.java index 6e20b59736..274f360ba4 100644 --- a/spring-core/src/test/java/org/springframework/core/annotation/NestedRepeatableAnnotationsTests.java +++ b/spring-core/src/test/java/org/springframework/core/annotation/NestedRepeatableAnnotationsTests.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. @@ -109,7 +109,7 @@ class NestedRepeatableAnnotationsTests { @Test void streamRepeatableAnnotationsWithExplicitRepeatables_MergedAnnotationsApi() { RepeatableContainers repeatableContainers = - RepeatableContainers.of(A.class, A.Container.class).and(B.Container.class, B.class); + RepeatableContainers.explicitRepeatable(A.class, A.Container.class).plus(B.class, B.Container.class); Set annotations = MergedAnnotations.from(method, SearchStrategy.TYPE_HIERARCHY, repeatableContainers) .stream(A.class).collect(MergedAnnotationCollectors.toAnnotationSet()); // Merged, so we expect to find @A twice with values coming from @B(5) and @B(10). @@ -127,8 +127,8 @@ class NestedRepeatableAnnotationsTests { void findMergedRepeatableAnnotationsWithExplicitContainer_AnnotatedElementUtils() { Set annotations = AnnotatedElementUtils.findMergedRepeatableAnnotations(method, A.class, A.Container.class); // When findMergedRepeatableAnnotations(...) is invoked with an explicit container - // type, it uses RepeatableContainers.of(...) which limits the repeatable annotation - // support to a single container type. + // type, it uses RepeatableContainers.explicitRepeatable(...) which limits the + // repeatable annotation support to a single container type. // // In this test case, we are therefore limiting the support to @A.Container, which // means that @B.Container is unsupported and effectively ignored as a repeatable @@ -149,8 +149,8 @@ class NestedRepeatableAnnotationsTests { void getMergedRepeatableAnnotationsWithExplicitContainer_AnnotatedElementUtils() { Set annotations = AnnotatedElementUtils.getMergedRepeatableAnnotations(method, A.class, A.Container.class); // When getMergedRepeatableAnnotations(...) is invoked with an explicit container - // type, it uses RepeatableContainers.of(...) which limits the repeatable annotation - // support to a single container type. + // type, it uses RepeatableContainers.explicitRepeatable(...) which limits the + // repeatable annotation support to a single container type. // // In this test case, we are therefore limiting the support to @A.Container, which // means that @B.Container is unsupported and effectively ignored as a repeatable diff --git a/spring-core/src/test/java/org/springframework/core/annotation/RepeatableContainersTests.java b/spring-core/src/test/java/org/springframework/core/annotation/RepeatableContainersTests.java index a6fa03f3c1..c28fcff1f8 100644 --- a/spring-core/src/test/java/org/springframework/core/annotation/RepeatableContainersTests.java +++ b/spring-core/src/test/java/org/springframework/core/annotation/RepeatableContainersTests.java @@ -87,7 +87,7 @@ class RepeatableContainersTests { @Test void ofExplicitWhenNonRepeatableReturnsNull() { Object[] values = findRepeatedAnnotationValues( - RepeatableContainers.of(ExplicitRepeatable.class, ExplicitContainer.class), + RepeatableContainers.explicitRepeatable(ExplicitRepeatable.class, ExplicitContainer.class), NonRepeatableTestCase.class, NonRepeatable.class); assertThat(values).isNull(); } @@ -95,7 +95,7 @@ class RepeatableContainersTests { @Test void ofExplicitWhenStandardRepeatableContainerReturnsNull() { Object[] values = findRepeatedAnnotationValues( - RepeatableContainers.of(ExplicitRepeatable.class, ExplicitContainer.class), + RepeatableContainers.explicitRepeatable(ExplicitRepeatable.class, ExplicitContainer.class), StandardRepeatablesTestCase.class, StandardContainer.class); assertThat(values).isNull(); } @@ -103,14 +103,14 @@ class RepeatableContainersTests { @Test void ofExplicitWhenContainerReturnsRepeats() { Object[] values = findRepeatedAnnotationValues( - RepeatableContainers.of(ExplicitRepeatable.class, ExplicitContainer.class), + RepeatableContainers.explicitRepeatable(ExplicitRepeatable.class, ExplicitContainer.class), ExplicitRepeatablesTestCase.class, ExplicitContainer.class); assertThat(values).containsExactly("a", "b"); } @Test void ofExplicitWhenContainerIsNullDeducesContainer() { - Object[] values = findRepeatedAnnotationValues(RepeatableContainers.of(StandardRepeatable.class, null), + Object[] values = findRepeatedAnnotationValues(RepeatableContainers.explicitRepeatable(StandardRepeatable.class, null), StandardRepeatablesTestCase.class, StandardContainer.class); assertThat(values).containsExactly("a", "b"); } @@ -118,7 +118,7 @@ class RepeatableContainersTests { @Test void ofExplicitWhenHasNoValueThrowsException() { assertThatExceptionOfType(AnnotationConfigurationException.class) - .isThrownBy(() -> RepeatableContainers.of(ExplicitRepeatable.class, InvalidNoValue.class)) + .isThrownBy(() -> RepeatableContainers.explicitRepeatable(ExplicitRepeatable.class, InvalidNoValue.class)) .withMessageContaining("Invalid declaration of container type [%s] for repeatable annotation [%s]", InvalidNoValue.class.getName(), ExplicitRepeatable.class.getName()); } @@ -126,7 +126,7 @@ class RepeatableContainersTests { @Test void ofExplicitWhenValueIsNotArrayThrowsException() { assertThatExceptionOfType(AnnotationConfigurationException.class) - .isThrownBy(() -> RepeatableContainers.of(ExplicitRepeatable.class, InvalidNotArray.class)) + .isThrownBy(() -> RepeatableContainers.explicitRepeatable(ExplicitRepeatable.class, InvalidNotArray.class)) .withMessage("Container type [%s] must declare a 'value' attribute for an array of type [%s]", InvalidNotArray.class.getName(), ExplicitRepeatable.class.getName()); } @@ -134,7 +134,7 @@ class RepeatableContainersTests { @Test void ofExplicitWhenValueIsArrayOfWrongTypeThrowsException() { assertThatExceptionOfType(AnnotationConfigurationException.class) - .isThrownBy(() -> RepeatableContainers.of(ExplicitRepeatable.class, InvalidWrongArrayType.class)) + .isThrownBy(() -> RepeatableContainers.explicitRepeatable(ExplicitRepeatable.class, InvalidWrongArrayType.class)) .withMessage("Container type [%s] must declare a 'value' attribute for an array of type [%s]", InvalidWrongArrayType.class.getName(), ExplicitRepeatable.class.getName()); } @@ -142,14 +142,14 @@ class RepeatableContainersTests { @Test void ofExplicitWhenAnnotationIsNullThrowsException() { assertThatIllegalArgumentException() - .isThrownBy(() -> RepeatableContainers.of(null, null)) + .isThrownBy(() -> RepeatableContainers.explicitRepeatable(null, null)) .withMessage("Repeatable must not be null"); } @Test void ofExplicitWhenContainerIsNullAndNotRepeatableThrowsException() { assertThatIllegalArgumentException() - .isThrownBy(() -> RepeatableContainers.of(ExplicitRepeatable.class, null)) + .isThrownBy(() -> RepeatableContainers.explicitRepeatable(ExplicitRepeatable.class, null)) .withMessage("Annotation type must be a repeatable annotation: failed to resolve container type for %s", ExplicitRepeatable.class.getName()); } @@ -159,7 +159,7 @@ class RepeatableContainersTests { @Test void standardAndExplicitReturnsRepeats() { RepeatableContainers repeatableContainers = RepeatableContainers.standardRepeatables() - .and(ExplicitContainer.class, ExplicitRepeatable.class); + .plus(ExplicitRepeatable.class, ExplicitContainer.class); assertThat(findRepeatedAnnotationValues(repeatableContainers, StandardRepeatablesTestCase.class, StandardContainer.class)) .containsExactly("a", "b"); assertThat(findRepeatedAnnotationValues(repeatableContainers, ExplicitRepeatablesTestCase.class, ExplicitContainer.class)) @@ -175,10 +175,10 @@ class RepeatableContainersTests { @Test void equalsAndHashcode() { - RepeatableContainers c1 = RepeatableContainers.of(ExplicitRepeatable.class, ExplicitContainer.class); - RepeatableContainers c2 = RepeatableContainers.of(ExplicitRepeatable.class, ExplicitContainer.class); + RepeatableContainers c1 = RepeatableContainers.explicitRepeatable(ExplicitRepeatable.class, ExplicitContainer.class); + RepeatableContainers c2 = RepeatableContainers.explicitRepeatable(ExplicitRepeatable.class, ExplicitContainer.class); RepeatableContainers c3 = RepeatableContainers.standardRepeatables(); - RepeatableContainers c4 = RepeatableContainers.standardRepeatables().and(ExplicitContainer.class, ExplicitRepeatable.class); + RepeatableContainers c4 = RepeatableContainers.standardRepeatables().plus(ExplicitRepeatable.class, ExplicitContainer.class); assertThat(c1).hasSameHashCodeAs(c2); assertThat(c1).isEqualTo(c1).isEqualTo(c2); assertThat(c1).isNotEqualTo(c3).isNotEqualTo(c4);