Improve exception for mixed explicit/implicit aliases with @AliasFor

Given the following improperly configured composed @RequestMapping
annotation:

@Retention(RetentionPolicy.RUNTIME)
@RequestMapping
@interface PostApi {

	@AliasFor("value")
	String[] path() default {};

	@AliasFor(annotation = RequestMapping.class, attribute = "path")
	String[] value() default {};
}

Prior to this commit, an attempt to process the above annotation
resulted in an exception similar to the following, which is not
especially helpful to discern the problem.

> Attribute 'value' in annotation [PostApi] must be declared as an
> @AliasFor 'path', not 'path'.

This commit improves the exception message for such scenarios,
resulting in an exception message similar to the following.

> Attribute 'value' in annotation [PostApi] must be declared as an
> @AliasFor attribute 'path' in annotation [PostApi], not attribute
> 'path' in annotation [RequestMapping].

Closes gh-24168
This commit is contained in:
Sam Brannen
2019-12-10 14:09:55 +01:00
parent 4466114cfa
commit 2bd821c909
2 changed files with 60 additions and 17 deletions

View File

@@ -160,11 +160,28 @@ class AnnotationTypeMappingsTests {
@Test
void forAnnotationTypeWhenAliasForToSelfAnnotatedToOtherAttribute() {
assertThatExceptionOfType(AnnotationConfigurationException.class).isThrownBy(() ->
AnnotationTypeMappings.forAnnotationType(AliasForToSelfAnnotatedToOtherAttribute.class))
.withMessage("Attribute 'b' in annotation ["
+ AliasForToSelfAnnotatedToOtherAttribute.class.getName()
+ "] must be declared as an @AliasFor 'a', not 'c'.");
String annotationType = AliasForToSelfAnnotatedToOtherAttribute.class.getName();
assertThatExceptionOfType(AnnotationConfigurationException.class)
.isThrownBy(() -> AnnotationTypeMappings.forAnnotationType(AliasForToSelfAnnotatedToOtherAttribute.class))
.withMessage("Attribute 'b' in annotation [" + annotationType
+ "] must be declared as an @AliasFor attribute 'a' in annotation [" + annotationType
+ "], not attribute 'c' in annotation [" + annotationType + "].");
}
@Test
void forAnnotationTypeWhenAliasForHasMixedImplicitAndExplicitAliases() {
assertMixedImplicitAndExplicitAliases(AliasForWithMixedImplicitAndExplicitAliasesV1.class, "b");
assertMixedImplicitAndExplicitAliases(AliasForWithMixedImplicitAndExplicitAliasesV2.class, "a");
}
private void assertMixedImplicitAndExplicitAliases(Class<? extends Annotation> annotationType, String overriddenAttribute) {
String annotationName = annotationType.getName();
String metaAnnotationName = AliasPair.class.getName();
assertThatExceptionOfType(AnnotationConfigurationException.class)
.isThrownBy(() -> AnnotationTypeMappings.forAnnotationType(annotationType))
.withMessage("Attribute 'b' in annotation [" + annotationName
+ "] must be declared as an @AliasFor attribute 'a' in annotation [" + annotationName
+ "], not attribute '" + overriddenAttribute + "' in annotation [" + metaAnnotationName + "].");
}
@Test
@@ -641,6 +658,42 @@ class AnnotationTypeMappingsTests {
String c() default "";
}
@Retention(RetentionPolicy.RUNTIME)
@interface AliasPair {
@AliasFor("b")
String a() default "";
@AliasFor("a")
String b() default "";
}
@Retention(RetentionPolicy.RUNTIME)
@AliasPair
@interface AliasForWithMixedImplicitAndExplicitAliasesV1 {
// attempted implicit alias via attribute override
@AliasFor(annotation = AliasPair.class, attribute = "b")
String b() default "";
// explicit local alias
@AliasFor("b")
String a() default "";
}
@Retention(RetentionPolicy.RUNTIME)
@AliasPair
@interface AliasForWithMixedImplicitAndExplicitAliasesV2 {
// attempted implicit alias via attribute override
@AliasFor(annotation = AliasPair.class, attribute = "a")
String b() default "";
// explicit local alias
@AliasFor("b")
String a() default "";
}
@Retention(RetentionPolicy.RUNTIME)
@interface AliasForNonMetaAnnotated {
@@ -712,16 +765,6 @@ class AnnotationTypeMappingsTests {
String alias() default "";
}
@Retention(RetentionPolicy.RUNTIME)
@interface AliasPair {
@AliasFor("b")
String a() default "";
@AliasFor("a")
String b() default "";
}
@Retention(RetentionPolicy.RUNTIME)
@interface ImplicitMirrorsTarget {