提交 42e7ade1 编写于 作者: J Juergen Hoeller

Tolerate unidirectional alias declaration for annotation attribute pair

Closes gh-23834
上级 dba7bf7e
......@@ -27,7 +27,6 @@ import java.util.HashSet;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
import java.util.function.BiFunction;
......@@ -179,30 +178,25 @@ final class AnnotationTypeMapping {
}
if (isAliasPair(target) && checkAliasPair) {
AliasFor targetAliasFor = target.getAnnotation(AliasFor.class);
if (targetAliasFor == null) {
throw new AnnotationConfigurationException(String.format(
"%s must be declared as an @AliasFor '%s'.",
StringUtils.capitalize(AttributeMethods.describe(target)),
attribute.getName()));
}
Method mirror = resolveAliasTarget(target, targetAliasFor, false);
if (!mirror.equals(attribute)) {
throw new AnnotationConfigurationException(String.format(
"%s must be declared as an @AliasFor '%s', not '%s'.",
StringUtils.capitalize(AttributeMethods.describe(target)),
attribute.getName(), mirror.getName()));
if (targetAliasFor != null) {
Method mirror = resolveAliasTarget(target, targetAliasFor, false);
if (!mirror.equals(attribute)) {
throw new AnnotationConfigurationException(String.format(
"%s must be declared as an @AliasFor '%s', not '%s'.",
StringUtils.capitalize(AttributeMethods.describe(target)),
attribute.getName(), mirror.getName()));
}
}
}
return target;
}
private boolean isAliasPair(Method target) {
return target.getDeclaringClass().equals(this.annotationType);
return (this.annotationType == target.getDeclaringClass());
}
private boolean isCompatibleReturnType(Class<?> attributeType, Class<?> targetType) {
return Objects.equals(attributeType, targetType) ||
Objects.equals(attributeType, targetType.getComponentType());
return (attributeType == targetType || attributeType == targetType.getComponentType());
}
private void processAliases() {
......
......@@ -1200,7 +1200,7 @@ class AnnotatedElementUtilsTests {
@AliasFor("basePackages")
String[] value() default {};
@AliasFor("value")
// Intentionally no alias declaration for "value"
String[] basePackages() default {};
Filter[] excludeFilters() default {};
......@@ -1485,7 +1485,7 @@ class AnnotatedElementUtilsTests {
}
@Retention(RetentionPolicy.RUNTIME)
static @interface ValueAttribute {
@interface ValueAttribute {
String[] value();
......@@ -1493,7 +1493,7 @@ class AnnotatedElementUtilsTests {
@Retention(RetentionPolicy.RUNTIME)
@ValueAttribute("FromValueAttributeMeta")
static @interface ValueAttributeMeta {
@interface ValueAttributeMeta {
@AliasFor("alias")
String[] value() default {};
......@@ -1505,7 +1505,7 @@ class AnnotatedElementUtilsTests {
@Retention(RetentionPolicy.RUNTIME)
@ValueAttributeMeta("FromValueAttributeMetaMeta")
static @interface ValueAttributeMetaMeta {
@interface ValueAttributeMetaMeta {
}
@ValueAttributeMetaMeta
......
......@@ -158,15 +158,6 @@ class AnnotationTypeMappingsTests {
+ "] must declare the same return type.");
}
@Test
void forAnnotationTypeWhenAliasForToSelfNonAnnotatedAttribute() {
assertThatExceptionOfType(AnnotationConfigurationException.class).isThrownBy(() ->
AnnotationTypeMappings.forAnnotationType(AliasForToSelfNonAnnotatedAttribute.class))
.withMessage("Attribute 'other' in annotation ["
+ AliasForToSelfNonAnnotatedAttribute.class.getName()
+ "] must be declared as an @AliasFor 'test'.");
}
@Test
void forAnnotationTypeWhenAliasForToSelfAnnotatedToOtherAttribute() {
assertThatExceptionOfType(AnnotationConfigurationException.class).isThrownBy(() ->
......@@ -554,67 +545,67 @@ class AnnotationTypeMappingsTests {
}
@Retention(RetentionPolicy.RUNTIME)
static @interface SimpleAnnotation {
@interface SimpleAnnotation {
}
@Retention(RetentionPolicy.RUNTIME)
@Inherited
@UsesSunMisc
static @interface WithSpringLangAnnotation {
@interface WithSpringLangAnnotation {
}
@Retention(RetentionPolicy.RUNTIME)
@A
@B
static @interface MetaAnnotated {
@interface MetaAnnotated {
}
@Retention(RetentionPolicy.RUNTIME)
@AA
@AB
static @interface A {
@interface A {
}
@Retention(RetentionPolicy.RUNTIME)
static @interface AA {
@interface AA {
}
@Retention(RetentionPolicy.RUNTIME)
@ABC
static @interface AB {
@interface AB {
}
@Retention(RetentionPolicy.RUNTIME)
static @interface ABC {
@interface ABC {
}
@Retention(RetentionPolicy.RUNTIME)
static @interface B {
@interface B {
}
@Retention(RetentionPolicy.RUNTIME)
@Repeating
@Repeating
static @interface WithRepeatedMetaAnnotations {
@interface WithRepeatedMetaAnnotations {
}
@Retention(RetentionPolicy.RUNTIME)
@Repeatable(Repeatings.class)
static @interface Repeating {
@interface Repeating {
}
@Retention(RetentionPolicy.RUNTIME)
static @interface Repeatings {
@interface Repeatings {
Repeating[] value();
......@@ -622,24 +613,24 @@ class AnnotationTypeMappingsTests {
@Retention(RetentionPolicy.RUNTIME)
@SelfAnnotated
static @interface SelfAnnotated {
@interface SelfAnnotated {
}
@Retention(RetentionPolicy.RUNTIME)
@LoopB
static @interface LoopA {
@interface LoopA {
}
@Retention(RetentionPolicy.RUNTIME)
@LoopA
static @interface LoopB {
@interface LoopB {
}
@Retention(RetentionPolicy.RUNTIME)
static @interface AliasForWithBothValueAndAttribute {
@interface AliasForWithBothValueAndAttribute {
@AliasFor(value = "bar", attribute = "foo")
String test();
......@@ -647,7 +638,7 @@ class AnnotationTypeMappingsTests {
}
@Retention(RetentionPolicy.RUNTIME)
static @interface AliasForToSelfNonExistingAttribute {
@interface AliasForToSelfNonExistingAttribute {
@AliasFor("missing")
String test() default "";
......@@ -658,7 +649,7 @@ class AnnotationTypeMappingsTests {
@Retention(RetentionPolicy.RUNTIME)
@AliasForToOtherNonExistingAttributeTarget
static @interface AliasForToOtherNonExistingAttribute {
@interface AliasForToOtherNonExistingAttribute {
@AliasFor(annotation = AliasForToOtherNonExistingAttributeTarget.class, attribute = "missing")
String test() default "";
......@@ -666,14 +657,14 @@ class AnnotationTypeMappingsTests {
}
@Retention(RetentionPolicy.RUNTIME)
static @interface AliasForToOtherNonExistingAttributeTarget {
@interface AliasForToOtherNonExistingAttributeTarget {
String other() default "";
}
@Retention(RetentionPolicy.RUNTIME)
static @interface AliasForToSelf {
@interface AliasForToSelf {
@AliasFor("test")
String test() default "";
......@@ -682,7 +673,7 @@ class AnnotationTypeMappingsTests {
@Retention(RetentionPolicy.RUNTIME)
@AliasForWithArrayCompatibleReturnTypesTarget
static @interface AliasForWithArrayCompatibleReturnTypes {
@interface AliasForWithArrayCompatibleReturnTypes {
@AliasFor(annotation = AliasForWithArrayCompatibleReturnTypesTarget.class)
String test() default "";
......@@ -690,14 +681,14 @@ class AnnotationTypeMappingsTests {
}
@Retention(RetentionPolicy.RUNTIME)
static @interface AliasForWithArrayCompatibleReturnTypesTarget {
@interface AliasForWithArrayCompatibleReturnTypesTarget {
String[] test() default {};
}
@Retention(RetentionPolicy.RUNTIME)
static @interface AliasForWithIncompatibleReturnTypes {
@interface AliasForWithIncompatibleReturnTypes {
@AliasFor(annotation = AliasForWithIncompatibleReturnTypesTarget.class)
String[] test() default {};
......@@ -705,24 +696,14 @@ class AnnotationTypeMappingsTests {
}
@Retention(RetentionPolicy.RUNTIME)
static @interface AliasForWithIncompatibleReturnTypesTarget {
String test() default "";
}
@Retention(RetentionPolicy.RUNTIME)
static @interface AliasForToSelfNonAnnotatedAttribute {
@interface AliasForWithIncompatibleReturnTypesTarget {
@AliasFor("other")
String test() default "";
String other() default "";
}
@Retention(RetentionPolicy.RUNTIME)
static @interface AliasForToSelfAnnotatedToOtherAttribute {
@interface AliasForToSelfAnnotatedToOtherAttribute {
@AliasFor("b")
String a() default "";
......@@ -736,7 +717,7 @@ class AnnotationTypeMappingsTests {
}
@Retention(RetentionPolicy.RUNTIME)
static @interface AliasForNonMetaAnnotated {
@interface AliasForNonMetaAnnotated {
@AliasFor(annotation = AliasForNonMetaAnnotatedTarget.class)
String test() default "";
......@@ -744,14 +725,14 @@ class AnnotationTypeMappingsTests {
}
@Retention(RetentionPolicy.RUNTIME)
static @interface AliasForNonMetaAnnotatedTarget {
@interface AliasForNonMetaAnnotatedTarget {
String test() default "";
}
@Retention(RetentionPolicy.RUNTIME)
static @interface AliasForSelfWithDifferentDefaults {
@interface AliasForSelfWithDifferentDefaults {
@AliasFor("b")
String a() default "a";
......@@ -762,7 +743,7 @@ class AnnotationTypeMappingsTests {
}
@Retention(RetentionPolicy.RUNTIME)
static @interface AliasForSelfWithMissingDefault {
@interface AliasForSelfWithMissingDefault {
@AliasFor("b")
String a() default "a";
......@@ -774,7 +755,7 @@ class AnnotationTypeMappingsTests {
@Retention(RetentionPolicy.RUNTIME)
@AliasWithExplicitMirrorAndDifferentDefaultsTarget
static @interface AliasWithExplicitMirrorAndDifferentDefaults {
@interface AliasWithExplicitMirrorAndDifferentDefaults {
@AliasFor(annotation = AliasWithExplicitMirrorAndDifferentDefaultsTarget.class, attribute = "a")
String a() default "x";
......@@ -788,7 +769,7 @@ class AnnotationTypeMappingsTests {
}
@Retention(RetentionPolicy.RUNTIME)
static @interface AliasWithExplicitMirrorAndDifferentDefaultsTarget {
@interface AliasWithExplicitMirrorAndDifferentDefaultsTarget {
String a() default "";
......@@ -796,7 +777,7 @@ class AnnotationTypeMappingsTests {
@Retention(RetentionPolicy.RUNTIME)
@MappedTarget
static @interface Mapped {
@interface Mapped {
String convention() default "";
......@@ -806,7 +787,7 @@ class AnnotationTypeMappingsTests {
}
@Retention(RetentionPolicy.RUNTIME)
static @interface MappedTarget {
@interface MappedTarget {
String convention() default "";
......@@ -815,7 +796,7 @@ class AnnotationTypeMappingsTests {
}
@Retention(RetentionPolicy.RUNTIME)
static @interface AliasPair {
@interface AliasPair {
@AliasFor("b")
String a() default "";
......@@ -827,7 +808,7 @@ class AnnotationTypeMappingsTests {
@Retention(RetentionPolicy.RUNTIME)
@ImplicitMirrorsTarget
static @interface ImplicitMirrors {
@interface ImplicitMirrors {
@AliasFor(annotation = ImplicitMirrorsTarget.class, attribute = "c")
String a() default "";
......@@ -838,7 +819,7 @@ class AnnotationTypeMappingsTests {
}
@Retention(RetentionPolicy.RUNTIME)
static @interface ImplicitMirrorsTarget {
@interface ImplicitMirrorsTarget {
@AliasFor("d")
String c() default "";
......@@ -850,7 +831,7 @@ class AnnotationTypeMappingsTests {
@Retention(RetentionPolicy.RUNTIME)
@ThreeDeepB
static @interface ThreeDeepA {
@interface ThreeDeepA {
@AliasFor(annotation = ThreeDeepB.class, attribute = "b1")
String a1() default "";
......@@ -871,7 +852,7 @@ class AnnotationTypeMappingsTests {
@Retention(RetentionPolicy.RUNTIME)
@ThreeDeepC
static @interface ThreeDeepB {
@interface ThreeDeepB {
@AliasFor(annotation = ThreeDeepC.class, attribute = "c1")
String b1() default "";
......@@ -882,7 +863,7 @@ class AnnotationTypeMappingsTests {
}
@Retention(RetentionPolicy.RUNTIME)
static @interface ThreeDeepC {
@interface ThreeDeepC {
String c1() default "";
......@@ -892,7 +873,7 @@ class AnnotationTypeMappingsTests {
@Retention(RetentionPolicy.RUNTIME)
@DefinedAttributesTarget(a = "test")
static @interface DefinedAttributes {
@interface DefinedAttributes {
@AliasFor(annotation = DefinedAttributesTarget.class, attribute = "b")
String value();
......@@ -900,7 +881,7 @@ class AnnotationTypeMappingsTests {
}
@Retention(RetentionPolicy.RUNTIME)
static @interface DefinedAttributesTarget {
@interface DefinedAttributesTarget {
String a();
......@@ -935,7 +916,7 @@ class AnnotationTypeMappingsTests {
@Retention(RetentionPolicy.RUNTIME)
@MulipleRoutesToAliasB
static @interface MulipleRoutesToAliasA {
@interface MulipleRoutesToAliasA {
@AliasFor(annotation = MulipleRoutesToAliasB.class, attribute = "b2")
String a1() default "";
......@@ -944,7 +925,7 @@ class AnnotationTypeMappingsTests {
@Retention(RetentionPolicy.RUNTIME)
@MulipleRoutesToAliasC
static @interface MulipleRoutesToAliasB {
@interface MulipleRoutesToAliasB {
@AliasFor(annotation = MulipleRoutesToAliasC.class, attribute = "c2")
String b1() default "";
......@@ -958,7 +939,7 @@ class AnnotationTypeMappingsTests {
}
@Retention(RetentionPolicy.RUNTIME)
static @interface MulipleRoutesToAliasC {
@interface MulipleRoutesToAliasC {
@AliasFor("c2")
String c1() default "";
......@@ -970,14 +951,14 @@ class AnnotationTypeMappingsTests {
@Retention(RetentionPolicy.RUNTIME)
@ConventionToExplicitAliasesTarget
static @interface ConventionToExplicitAliases {
@interface ConventionToExplicitAliases {
String test() default "";
}
@Retention(RetentionPolicy.RUNTIME)
static @interface ConventionToExplicitAliasesTarget {
@interface ConventionToExplicitAliasesTarget {
@AliasFor("test")
String value() default "";
......@@ -988,28 +969,28 @@ class AnnotationTypeMappingsTests {
}
@Retention(RetentionPolicy.RUNTIME)
static @interface ClassValue {
@interface ClassValue {
Class<?> value();
}
@Retention(RetentionPolicy.RUNTIME)
static @interface ClassValueWithDefault {
@interface ClassValueWithDefault {
Class<?> value() default InputStream.class;
}
@Retention(RetentionPolicy.RUNTIME)
static @interface ClassArrayValueWithDefault {
@interface ClassArrayValueWithDefault {
Class<?>[] value() default { InputStream.class, OutputStream.class };
}
@Retention(RetentionPolicy.RUNTIME)
static @interface NestedValue {
@interface NestedValue {
ClassValue value() default @ClassValue(InputStream.class);
......
......@@ -556,16 +556,6 @@ class AnnotationUtilsTests {
assertThat(values).isEqualTo(asList("A", "B", "C", "meta1"));
}
@Test
void getRepeatableAnnotationsDeclaredOnClassWithMissingAttributeAliasDeclaration() throws Exception {
assertThatExceptionOfType(AnnotationConfigurationException.class).isThrownBy(() ->
getRepeatableAnnotations(BrokenConfigHierarchyTestCase.class, BrokenContextConfig.class, BrokenHierarchy.class))
.withMessageStartingWith("Attribute 'value' in")
.withMessageContaining(BrokenContextConfig.class.getName())
.withMessageContaining("@AliasFor 'location'");
}
@Test
void getRepeatableAnnotationsDeclaredOnClassWithAttributeAliases() {
final List<String> expectedLocations = asList("A", "B");
......@@ -1415,17 +1405,6 @@ class AnnotationUtilsTests {
Class<?> klass() default Object.class;
}
@Retention(RetentionPolicy.RUNTIME)
@interface BrokenContextConfig {
// Intentionally missing:
// @AliasFor("location")
String value() default "";
@AliasFor("value")
String location() default "";
}
/**
* Mock of {@code org.springframework.test.context.ContextHierarchy}.
*/
......@@ -1434,19 +1413,10 @@ class AnnotationUtilsTests {
ContextConfig[] value();
}
@Retention(RetentionPolicy.RUNTIME)
@interface BrokenHierarchy {
BrokenContextConfig[] value();
}
@Hierarchy({@ContextConfig("A"), @ContextConfig(location = "B")})
static class ConfigHierarchyTestCase {
}
@BrokenHierarchy(@BrokenContextConfig)
static class BrokenConfigHierarchyTestCase {
}
@ContextConfig("simple.xml")
static class SimpleConfigTestCase {
}
......@@ -1825,13 +1795,13 @@ class AnnotationUtilsTests {
@Retention(RetentionPolicy.RUNTIME)
@Repeatable(TestRepeatableContainer.class)
static @interface TestRepeatable {
@interface TestRepeatable {
String value();
}
@Retention(RetentionPolicy.RUNTIME)
static @interface TestRepeatableContainer {
@interface TestRepeatableContainer {
TestRepeatable[] value();
}
......
......@@ -1308,18 +1308,6 @@ class MergedAnnotationsTests {
assertThat(values).containsExactly("A", "B", "C", "meta1");
}
@Test
void getRepeatableDeclaredOnClassWithMissingAttributeAliasDeclaration() {
RepeatableContainers containers = RepeatableContainers.of(
BrokenContextConfiguration.class, BrokenHierarchy.class);
assertThatExceptionOfType(AnnotationConfigurationException.class).isThrownBy(() ->
MergedAnnotations.from(BrokenHierarchyClass.class, SearchStrategy.TYPE_HIERARCHY, containers,
AnnotationFilter.PLAIN).get(BrokenHierarchy.class))
.withMessageStartingWith("Attribute 'value' in")
.withMessageContaining(BrokenContextConfiguration.class.getName())
.withMessageContaining("@AliasFor 'location'");
}
@Test
void getRepeatableDeclaredOnClassWithAttributeAliases() {
assertThat(MergedAnnotations.from(HierarchyClass.class).stream(
......@@ -1329,8 +1317,7 @@ class MergedAnnotationsTests {
MergedAnnotations annotations = MergedAnnotations.from(HierarchyClass.class,
SearchStrategy.DIRECT, containers, AnnotationFilter.NONE);
assertThat(annotations.stream(TestConfiguration.class).map(
annotation -> annotation.getString("location"))).containsExactly("A",
"B");
annotation -> annotation.getString("location"))).containsExactly("A", "B");
assertThat(annotations.stream(TestConfiguration.class).map(
annotation -> annotation.getString("value"))).containsExactly("A", "B");
}
......@@ -1488,17 +1475,6 @@ class MergedAnnotationsTests {
.withMessageContaining("declares an alias for 'bar' which is not present");
}
@Test
void synthesizeWhenAttributeAliasWithoutMirroredAliasFor() throws Exception {
AliasForWithoutMirroredAliasFor annotation = AliasForWithoutMirroredAliasForClass.class.getAnnotation(
AliasForWithoutMirroredAliasFor.class);
assertThatExceptionOfType(AnnotationConfigurationException.class).isThrownBy(() ->
MergedAnnotation.from(annotation))
.withMessageStartingWith("Attribute 'bar' in")
.withMessageContaining(AliasForWithoutMirroredAliasFor.class.getName())
.withMessageContaining("@AliasFor 'foo'");
}
@Test
void synthesizeWhenAttributeAliasWithMirroredAliasForWrongAttribute()
throws Exception {
......@@ -3055,15 +3031,6 @@ class MergedAnnotationsTests {
}
}
@Retention(RetentionPolicy.RUNTIME)
@interface BrokenContextConfiguration {
String value() default "";
@AliasFor("value")
String location() default "";
}
@Retention(RetentionPolicy.RUNTIME)
@interface TestConfiguration {
......@@ -3082,20 +3049,10 @@ class MergedAnnotationsTests {
TestConfiguration[] value();
}
@Retention(RetentionPolicy.RUNTIME)
@interface BrokenHierarchy {
BrokenContextConfiguration[] value();
}
@Hierarchy({ @TestConfiguration("A"), @TestConfiguration(location = "B") })
static class HierarchyClass {
}
@BrokenHierarchy(@BrokenContextConfiguration)
static class BrokenHierarchyClass {
}
@TestConfiguration("simple.xml")
static class TestConfigurationClass {
}
......@@ -3544,7 +3501,7 @@ class MergedAnnotationsTests {
}
@Retention(RetentionPolicy.RUNTIME)
static @interface ValueAttribute {
@interface ValueAttribute {
String[] value();
......@@ -3552,7 +3509,7 @@ class MergedAnnotationsTests {
@Retention(RetentionPolicy.RUNTIME)
@ValueAttribute("FromValueAttributeMeta")
static @interface ValueAttributeMeta {
@interface ValueAttributeMeta {
String[] value() default {};
......@@ -3560,7 +3517,7 @@ class MergedAnnotationsTests {
@Retention(RetentionPolicy.RUNTIME)
@ValueAttributeMeta("FromValueAttributeMetaMeta")
static @interface ValueAttributeMetaMeta {
@interface ValueAttributeMetaMeta {
}
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册