Polish MergedAnnotation support

This commit is contained in:
Sam Brannen 2019-05-13 13:59:26 +02:00
parent cfc4a59135
commit 785e8d8116
7 changed files with 40 additions and 58 deletions

View File

@ -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(),

View File

@ -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()));
}

View File

@ -77,7 +77,7 @@ public interface MergedAnnotation<A extends Annotation> {
* 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<Class<? extends Annotation>> getTypeHierarchy();

View File

@ -35,10 +35,10 @@ import org.springframework.lang.Nullable;
*
* <ul>
* <li>Explicit and Implicit {@link AliasFor @AliasFor} declarations on one or
* more attributes within the annotation.</li>
* <li>Explicit {@link AliasFor @AliasFor} declarations for a meta-annotation.</li>
* more attributes within the annotation</li>
* <li>Explicit {@link AliasFor @AliasFor} declarations for a meta-annotation</li>
* <li>Convention based attribute aliases for a meta-annotation</li>
* <li>From a meta-annotation declaration.</li>
* <li>From a meta-annotation declaration</li>
* </ul>
*
* <p>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 -&gt; a.getString("value")).forEach(System.out::println);
* </pre>
*
* @author Phillip Webb

View File

@ -163,11 +163,8 @@ public abstract class RepeatableContainers {
private static Object computeRepeatedAnnotationsMethod(Class<? extends Annotation> 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");

View File

@ -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

View File

@ -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();