From 785e8d81165859681732f0b315ba7d7b93bd825c Mon Sep 17 00:00:00 2001 From: Sam Brannen Date: Mon, 13 May 2019 13:59:26 +0200 Subject: [PATCH] Polish MergedAnnotation support --- .../annotation/AnnotationTypeMapping.java | 2 +- .../core/annotation/AttributeMethods.java | 6 +- .../core/annotation/MergedAnnotation.java | 2 +- .../core/annotation/MergedAnnotations.java | 8 +-- .../core/annotation/RepeatableContainers.java | 9 +-- .../AnnotationTypeMappingsTests.java | 2 +- .../annotation/AttributeMethodsTests.java | 69 ++++++++----------- 7 files changed, 40 insertions(+), 58 deletions(-) diff --git a/spring-core/src/main/java/org/springframework/core/annotation/AnnotationTypeMapping.java b/spring-core/src/main/java/org/springframework/core/annotation/AnnotationTypeMapping.java index a48b85c3dc..23b011fb5e 100644 --- a/spring-core/src/main/java/org/springframework/core/annotation/AnnotationTypeMapping.java +++ b/spring-core/src/main/java/org/springframework/core/annotation/AnnotationTypeMapping.java @@ -647,7 +647,7 @@ final class AnnotationTypeMapping { !ObjectUtils.nullSafeEquals(lastValue, value)) { String on = (source != null) ? " declared on " + source : ""; throw new AnnotationConfigurationException(String.format( - "Different @AliasFor mirror values for annotation [%s]%s, attribute '%s' " + + "Different @AliasFor mirror values for annotation [%s]%s; attribute '%s' " + "and its alias '%s' are declared with values of [%s] and [%s].", getAnnotationType().getName(), on, attributes.get(result).getName(), diff --git a/spring-core/src/main/java/org/springframework/core/annotation/AttributeMethods.java b/spring-core/src/main/java/org/springframework/core/annotation/AttributeMethods.java index 6d1b3e32f4..c04bf172ff 100644 --- a/spring-core/src/main/java/org/springframework/core/annotation/AttributeMethods.java +++ b/spring-core/src/main/java/org/springframework/core/annotation/AttributeMethods.java @@ -89,11 +89,11 @@ final class AttributeMethods { /** - * Determine if this instance only contains only a single attribute named + * Determine if this instance only contains a single attribute named * {@code value}. - * @return {@code true} if this is only a value attribute + * @return {@code true} if there is only a value attribute */ - boolean isOnlyValueAttribute() { + boolean hasOnlyValueAttribute() { return (this.attributeMethods.length == 1 && MergedAnnotation.VALUE.equals(this.attributeMethods[0].getName())); } diff --git a/spring-core/src/main/java/org/springframework/core/annotation/MergedAnnotation.java b/spring-core/src/main/java/org/springframework/core/annotation/MergedAnnotation.java index ef350a231e..89fae555d7 100644 --- a/spring-core/src/main/java/org/springframework/core/annotation/MergedAnnotation.java +++ b/spring-core/src/main/java/org/springframework/core/annotation/MergedAnnotation.java @@ -77,7 +77,7 @@ public interface MergedAnnotation { * Return a complete type hierarchy from this annotation to the * {@link #getRoot() root}. Provides a useful way to uniquely identify a * merged annotation instance. - * @return the type heirarchy for the annotation + * @return the type hierarchy for the annotation * @see MergedAnnotationPredicates#unique(Function) */ List> getTypeHierarchy(); diff --git a/spring-core/src/main/java/org/springframework/core/annotation/MergedAnnotations.java b/spring-core/src/main/java/org/springframework/core/annotation/MergedAnnotations.java index 8c3d8056b1..2b9c7997b5 100644 --- a/spring-core/src/main/java/org/springframework/core/annotation/MergedAnnotations.java +++ b/spring-core/src/main/java/org/springframework/core/annotation/MergedAnnotations.java @@ -35,10 +35,10 @@ import org.springframework.lang.Nullable; * *
    *
  • Explicit and Implicit {@link AliasFor @AliasFor} declarations on one or - * more attributes within the annotation.
  • - *
  • Explicit {@link AliasFor @AliasFor} declarations for a meta-annotation.
  • + * more attributes within the annotation + *
  • Explicit {@link AliasFor @AliasFor} declarations for a meta-annotation
  • *
  • Convention based attribute aliases for a meta-annotation
  • - *
  • From a meta-annotation declaration.
  • + *
  • From a meta-annotation declaration
  • *
* *

For example, a {@code @PostMapping} annotation might be defined as follows: @@ -116,7 +116,7 @@ import org.springframework.lang.Nullable; * // get all ExampleAnnotation declarations (including any meta-annotations) and * // print the merged "value" attributes * mergedAnnotations.stream(ExampleAnnotation.class).map( - * a -> a.getString("value")).forEach(System.out::println); + * a -> a.getString("value")).forEach(System.out::println); * * * @author Phillip Webb 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 6d1111c628..01cb98c3fa 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 @@ -163,11 +163,8 @@ public abstract class RepeatableContainers { private static Object computeRepeatedAnnotationsMethod(Class annotationType) { AttributeMethods methods = AttributeMethods.forAnnotationType(annotationType); - if (methods.isOnlyValueAttribute()) { - Method method = methods.get("value"); - if (method == null) { - return NONE; - } + if (methods.hasOnlyValueAttribute()) { + Method method = methods.get(0); Class returnType = method.getReturnType(); if (returnType.isArray()) { Class componentType = returnType.getComponentType(); @@ -201,7 +198,7 @@ public abstract class RepeatableContainers { if (container == null) { container = deduceContainer(repeatable); } - Method valueMethod = AttributeMethods.forAnnotationType(container).get("value"); + Method valueMethod = AttributeMethods.forAnnotationType(container).get(MergedAnnotation.VALUE); try { if (valueMethod == null) { throw new NoSuchMethodException("No value method found"); diff --git a/spring-core/src/test/java/org/springframework/core/annotation/AnnotationTypeMappingsTests.java b/spring-core/src/test/java/org/springframework/core/annotation/AnnotationTypeMappingsTests.java index 94460fa13d..1b7fec17db 100644 --- a/spring-core/src/test/java/org/springframework/core/annotation/AnnotationTypeMappingsTests.java +++ b/spring-core/src/test/java/org/springframework/core/annotation/AnnotationTypeMappingsTests.java @@ -394,7 +394,7 @@ public class AnnotationTypeMappingsTests { .withMessage("Different @AliasFor mirror values for annotation [" + AliasPair.class.getName() + "] declared on " + WithDifferentValueAliasPair.class.getName() - + ", attribute 'a' and its alias 'b' are declared with values of [test1] and [test2]."); + + "; attribute 'a' and its alias 'b' are declared with values of [test1] and [test2]."); } @Test diff --git a/spring-core/src/test/java/org/springframework/core/annotation/AttributeMethodsTests.java b/spring-core/src/test/java/org/springframework/core/annotation/AttributeMethodsTests.java index 7db120dc1b..f4de24915b 100644 --- a/spring-core/src/test/java/org/springframework/core/annotation/AttributeMethodsTests.java +++ b/spring-core/src/test/java/org/springframework/core/annotation/AttributeMethodsTests.java @@ -52,52 +52,46 @@ public class AttributeMethodsTests { @Test public void forAnnotationTypeWhenHasMultipleAttributesReturnsAttributes() { - AttributeMethods methods = AttributeMethods.forAnnotationType( - MultipleAttributes.class); + AttributeMethods methods = AttributeMethods.forAnnotationType(MultipleAttributes.class); assertThat(methods.get("value").getName()).isEqualTo("value"); assertThat(methods.get("intValue").getName()).isEqualTo("intValue"); - assertThat(getAll(methods)).flatExtracting(Method::getName).containsExactly( - "intValue", "value"); + assertThat(getAll(methods)).flatExtracting(Method::getName).containsExactly("intValue", "value"); } @Test - public void isOnlyValueAttributeWhenHasOnlyValueAttributeReturnsTrue() { + public void hasOnlyValueAttributeWhenHasOnlyValueAttributeReturnsTrue() { AttributeMethods methods = AttributeMethods.forAnnotationType(ValueOnly.class); - assertThat(methods.isOnlyValueAttribute()).isTrue(); + assertThat(methods.hasOnlyValueAttribute()).isTrue(); } @Test - public void isOnlyValueAttributeWhenHasOnlySingleNonValueAttributeReturnsFalse() { + public void hasOnlyValueAttributeWhenHasOnlySingleNonValueAttributeReturnsFalse() { AttributeMethods methods = AttributeMethods.forAnnotationType(NonValueOnly.class); - assertThat(methods.isOnlyValueAttribute()).isFalse(); + assertThat(methods.hasOnlyValueAttribute()).isFalse(); } @Test - public void isOnlyValueAttributeWhenHasOnlyMultipleAttributesIncludingValueReturnsFalse() { - AttributeMethods methods = AttributeMethods.forAnnotationType( - MultipleAttributes.class); - assertThat(methods.isOnlyValueAttribute()).isFalse(); + public void hasOnlyValueAttributeWhenHasOnlyMultipleAttributesIncludingValueReturnsFalse() { + AttributeMethods methods = AttributeMethods.forAnnotationType(MultipleAttributes.class); + assertThat(methods.hasOnlyValueAttribute()).isFalse(); } @Test public void indexOfNameReturnsIndex() { - AttributeMethods methods = AttributeMethods.forAnnotationType( - MultipleAttributes.class); + AttributeMethods methods = AttributeMethods.forAnnotationType(MultipleAttributes.class); assertThat(methods.indexOf("value")).isEqualTo(1); } @Test public void indexOfMethodReturnsIndex() throws Exception { - AttributeMethods methods = AttributeMethods.forAnnotationType( - MultipleAttributes.class); + AttributeMethods methods = AttributeMethods.forAnnotationType(MultipleAttributes.class); Method method = MultipleAttributes.class.getDeclaredMethod("value"); assertThat(methods.indexOf(method)).isEqualTo(1); } @Test public void sizeReturnsSize() { - AttributeMethods methods = AttributeMethods.forAnnotationType( - MultipleAttributes.class); + AttributeMethods methods = AttributeMethods.forAnnotationType(MultipleAttributes.class); assertThat(methods.size()).isEqualTo(2); } @@ -109,8 +103,7 @@ public class AttributeMethodsTests { @Test public void canThrowTypeNotPresentExceptionWhenHasClassArrayAttributeReturnsTrue() { - AttributeMethods methods = AttributeMethods.forAnnotationType( - ClassArrayValue.class); + AttributeMethods methods = AttributeMethods.forAnnotationType(ClassArrayValue.class); assertThat(methods.canThrowTypeNotPresentException(0)).isTrue(); } @@ -122,15 +115,13 @@ public class AttributeMethodsTests { @Test public void hasDefaultValueMethodWhenHasDefaultValueMethodReturnsTrue() { - AttributeMethods methods = AttributeMethods.forAnnotationType( - DefaultValueAttribute.class); + AttributeMethods methods = AttributeMethods.forAnnotationType(DefaultValueAttribute.class); assertThat(methods.hasDefaultValueMethod()).isTrue(); } @Test public void hasDefaultValueMethodWhenHasNoDefaultValueMethodsReturnsFalse() { - AttributeMethods methods = AttributeMethods.forAnnotationType( - MultipleAttributes.class); + AttributeMethods methods = AttributeMethods.forAnnotationType(MultipleAttributes.class); assertThat(methods.hasDefaultValueMethod()).isFalse(); } @@ -138,8 +129,7 @@ public class AttributeMethodsTests { public void isValidWhenHasTypeNotPresentExceptionReturnsFalse() { ClassValue annotation = mockAnnotation(ClassValue.class); given(annotation.value()).willThrow(TypeNotPresentException.class); - AttributeMethods attributes = AttributeMethods.forAnnotationType( - annotation.annotationType()); + AttributeMethods attributes = AttributeMethods.forAnnotationType(annotation.annotationType()); assertThat(attributes.isValid(annotation)).isFalse(); } @@ -148,8 +138,7 @@ public class AttributeMethodsTests { public void isValidWhenDoesNotHaveTypeNotPresentExceptionReturnsTrue() { ClassValue annotation = mock(ClassValue.class); given(annotation.value()).willReturn((Class) InputStream.class); - AttributeMethods attributes = AttributeMethods.forAnnotationType( - annotation.annotationType()); + AttributeMethods attributes = AttributeMethods.forAnnotationType(annotation.annotationType()); assertThat(attributes.isValid(annotation)).isTrue(); } @@ -157,10 +146,8 @@ public class AttributeMethodsTests { public void validateWhenHasTypeNotPresentExceptionThrowsException() { ClassValue annotation = mockAnnotation(ClassValue.class); given(annotation.value()).willThrow(TypeNotPresentException.class); - AttributeMethods attributes = AttributeMethods.forAnnotationType( - annotation.annotationType()); - assertThatIllegalStateException().isThrownBy(() -> - attributes.validate(annotation)); + AttributeMethods attributes = AttributeMethods.forAnnotationType(annotation.annotationType()); + assertThatIllegalStateException().isThrownBy(() -> attributes.validate(annotation)); } @Test @@ -168,8 +155,7 @@ public class AttributeMethodsTests { public void validateWhenDoesNotHaveTypeNotPresentExceptionThrowsNothing() { ClassValue annotation = mockAnnotation(ClassValue.class); given(annotation.value()).willReturn((Class) InputStream.class); - AttributeMethods attributes = AttributeMethods.forAnnotationType( - annotation.annotationType()); + AttributeMethods attributes = AttributeMethods.forAnnotationType(annotation.annotationType()); attributes.validate(annotation); } @@ -189,12 +175,11 @@ public class AttributeMethodsTests { } @Retention(RetentionPolicy.RUNTIME) - static @interface NoAttributes { - + @interface NoAttributes { } @Retention(RetentionPolicy.RUNTIME) - static @interface MultipleAttributes { + @interface MultipleAttributes { int intValue(); @@ -203,35 +188,35 @@ public class AttributeMethodsTests { } @Retention(RetentionPolicy.RUNTIME) - static @interface ValueOnly { + @interface ValueOnly { String value(); } @Retention(RetentionPolicy.RUNTIME) - static @interface NonValueOnly { + @interface NonValueOnly { String test(); } @Retention(RetentionPolicy.RUNTIME) - static @interface ClassValue { + @interface ClassValue { Class value(); } @Retention(RetentionPolicy.RUNTIME) - static @interface ClassArrayValue { + @interface ClassArrayValue { Class[] value(); } @Retention(RetentionPolicy.RUNTIME) - static @interface DefaultValueAttribute { + @interface DefaultValueAttribute { String one();