Ensure @AliasFor overrides attribute in correct meta-annotation

Prior to this commit, an explicit override for an attribute in a
meta-annotation configured via @AliasFor could potentially result in an
incorrect override of an attribute of the same name but in the wrong
meta-annotation.

This commit fixes the algorithm in getAliasedAttributeName(Method,
Class) in AnnotationUtils by ensuring that an explicit attribute
override is only applied to the configured target meta-annotation
(i.e., configured via the 'annotation' attribute in @AliasFor).

Issue: SPR-13325
This commit is contained in:
Sam Brannen
2015-08-06 19:04:08 +02:00
parent 1a659e3c1d
commit c8d604bf05
3 changed files with 62 additions and 0 deletions

View File

@@ -491,6 +491,30 @@ public class AnnotatedElementUtilsTests {
assertEquals("TX qualifier via synthesized annotation.", "aliasForQualifier", annotation.qualifier());
}
@Test
public void findMergedAnnotationForMultipleMetaAnnotationsWithClashingAttributeNames() {
final String[] xmlLocations = new String[] { "test.xml" };
final String[] propFiles = new String[] { "test.properties" };
Class<?> element = AliasedComposedContextConfigAndTestPropSourceClass.class;
ContextConfig contextConfig = findMergedAnnotation(element, ContextConfig.class);
assertNotNull("@ContextConfig on " + element, contextConfig);
assertArrayEquals("locations", xmlLocations, contextConfig.locations());
assertArrayEquals("value", xmlLocations, contextConfig.value());
// Synthesized annotation
TestPropSource testPropSource = AnnotationUtils.findAnnotation(element, TestPropSource.class);
assertArrayEquals("locations", propFiles, testPropSource.locations());
assertArrayEquals("value", propFiles, testPropSource.value());
// Merged annotation
testPropSource = findMergedAnnotation(element, TestPropSource.class);
assertNotNull("@TestPropSource on " + element, testPropSource);
assertArrayEquals("locations", propFiles, testPropSource.locations());
assertArrayEquals("value", propFiles, testPropSource.value());
}
@Test
public void findMergedAnnotationAttributesOnClassWithAttributeAliasInComposedAnnotationAndNestedAnnotationsInTargetAnnotation() {
Class<?> element = TestComponentScanClass.class;
@@ -622,6 +646,19 @@ public class AnnotatedElementUtilsTests {
@interface MetaAndLocalTxConfig {
}
/**
* Mock of {@code org.springframework.test.context.TestPropertySource}.
*/
@Retention(RetentionPolicy.RUNTIME)
@interface TestPropSource {
@AliasFor("locations")
String[] value() default {};
@AliasFor("value")
String[] locations() default {};
}
/**
* Mock of {@code org.springframework.test.context.ContextConfiguration}.
*/
@@ -679,6 +716,15 @@ public class AnnotatedElementUtilsTests {
String[] xmlConfigFiles();
}
@ContextConfig(locations = "shadowed.xml")
@TestPropSource(locations = "test.properties")
@Retention(RetentionPolicy.RUNTIME)
@interface AliasedComposedContextConfigAndTestPropSource {
@AliasFor(annotation = ContextConfig.class, attribute = "locations")
String[] xmlConfigFiles() default "default.xml";
}
/**
* Mock of {@code org.springframework.context.annotation.ComponentScan}
*/
@@ -855,6 +901,10 @@ public class AnnotatedElementUtilsTests {
static class InvalidAliasedComposedContextConfigClass {
}
@AliasedComposedContextConfigAndTestPropSource(xmlConfigFiles = "test.xml")
static class AliasedComposedContextConfigAndTestPropSourceClass {
}
@TestComponentScan(packages = "com.example.app.test")
static class TestComponentScanClass {
}

View File

@@ -675,6 +675,13 @@ public class AnnotationUtilsTests {
assertThat(set.size(), is(0));
}
@Test
public void getAliasedAttributeNameFromWrongTargetAnnotation() throws Exception {
Method attribute = AliasedComposedContextConfig.class.getDeclaredMethod("xmlConfigFile");
assertNull("xmlConfigFile is not an alias for @Component.",
getAliasedAttributeName(attribute, Component.class));
}
@Test
public void getAliasedAttributeNameFromAliasedComposedAnnotation() throws Exception {
Method attribute = AliasedComposedContextConfig.class.getDeclaredMethod("xmlConfigFile");