Complete migration of annotation utility methods
Delete `InternalAnnotationUtils` and `InternalAnnotatedElementUtils` and migrate exclusively to the new `MergedAnnotations` API. Closes gh-22562
This commit is contained in:
committed by
Juergen Hoeller
parent
a14bfe9a21
commit
37255afca4
@@ -70,12 +70,10 @@ public class AnnotationIntrospectionFailureTests {
|
||||
assertThat(AnnotatedElementUtils.getMergedAnnotationAttributes(
|
||||
withExampleMetaAnnotation,
|
||||
exampleMetaAnnotationClass)).isNull();
|
||||
// Ideally hasAnnotation should return false, however, it currently
|
||||
// detects annotations that might ultimately not load
|
||||
assertThat(AnnotatedElementUtils.hasAnnotation(withExampleMetaAnnotation,
|
||||
exampleAnnotationClass)).isTrue();
|
||||
exampleAnnotationClass)).isFalse();
|
||||
assertThat(AnnotatedElementUtils.hasAnnotation(withExampleMetaAnnotation,
|
||||
exampleMetaAnnotationClass)).isTrue();
|
||||
exampleMetaAnnotationClass)).isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
|
||||
@@ -38,7 +38,6 @@ import org.springframework.core.Ordered;
|
||||
import org.springframework.core.annotation.subpackage.NonPublicAnnotatedClass;
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.util.ClassUtils;
|
||||
|
||||
import static java.util.Arrays.*;
|
||||
import static java.util.stream.Collectors.*;
|
||||
@@ -487,8 +486,8 @@ public class AnnotationUtilsTests {
|
||||
@Test
|
||||
public void getAnnotationAttributesWithAttributeAliasesWithDifferentValues() throws Exception {
|
||||
exception.expect(AnnotationConfigurationException.class);
|
||||
exception.expectMessage(containsString("attribute 'value' and its alias 'path'"));
|
||||
exception.expectMessage(containsString("values of [{/enigma}] and [{/test}]"));
|
||||
exception.expectMessage(containsString("attribute 'path' and its alias 'value'"));
|
||||
exception.expectMessage(containsString("values of [{/test}] and [{/enigma}]"));
|
||||
|
||||
Method method = WebController.class.getMethod("handleMappedWithDifferentPathAndValueAttributes");
|
||||
WebMapping webMapping = method.getAnnotation(WebMapping.class);
|
||||
@@ -730,381 +729,6 @@ public class AnnotationUtilsTests {
|
||||
assertThat(set.size(), is(0));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getAttributeOverrideNameFromWrongTargetAnnotation() throws Exception {
|
||||
Method attribute = AliasedComposedContextConfig.class.getDeclaredMethod("xmlConfigFile");
|
||||
assertThat("xmlConfigFile is not an alias for @Component.",
|
||||
InternalAnnotationUtils.getAttributeOverrideName(attribute, Component.class), is(nullValue()));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getAttributeOverrideNameForNonAliasedAttribute() throws Exception {
|
||||
Method nonAliasedAttribute = ImplicitAliasesContextConfig.class.getDeclaredMethod("nonAliasedAttribute");
|
||||
assertThat(InternalAnnotationUtils.getAttributeOverrideName(nonAliasedAttribute, ContextConfig.class), is(nullValue()));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getAttributeOverrideNameFromAliasedComposedAnnotation() throws Exception {
|
||||
Method attribute = AliasedComposedContextConfig.class.getDeclaredMethod("xmlConfigFile");
|
||||
assertEquals("location", InternalAnnotationUtils.getAttributeOverrideName(attribute, ContextConfig.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getAttributeAliasNamesFromComposedAnnotationWithImplicitAliases() throws Exception {
|
||||
Method xmlFile = ImplicitAliasesContextConfig.class.getDeclaredMethod("xmlFile");
|
||||
Method groovyScript = ImplicitAliasesContextConfig.class.getDeclaredMethod("groovyScript");
|
||||
Method value = ImplicitAliasesContextConfig.class.getDeclaredMethod("value");
|
||||
Method location1 = ImplicitAliasesContextConfig.class.getDeclaredMethod("location1");
|
||||
Method location2 = ImplicitAliasesContextConfig.class.getDeclaredMethod("location2");
|
||||
Method location3 = ImplicitAliasesContextConfig.class.getDeclaredMethod("location3");
|
||||
|
||||
// Meta-annotation attribute overrides
|
||||
assertEquals("location", InternalAnnotationUtils.getAttributeOverrideName(xmlFile, ContextConfig.class));
|
||||
assertEquals("location", InternalAnnotationUtils.getAttributeOverrideName(groovyScript, ContextConfig.class));
|
||||
assertEquals("location", InternalAnnotationUtils.getAttributeOverrideName(value, ContextConfig.class));
|
||||
|
||||
// Implicit aliases
|
||||
assertThat(InternalAnnotationUtils.getAttributeAliasNames(xmlFile), containsInAnyOrder("value", "groovyScript", "location1", "location2", "location3"));
|
||||
assertThat(InternalAnnotationUtils.getAttributeAliasNames(groovyScript), containsInAnyOrder("value", "xmlFile", "location1", "location2", "location3"));
|
||||
assertThat(InternalAnnotationUtils.getAttributeAliasNames(value), containsInAnyOrder("xmlFile", "groovyScript", "location1", "location2", "location3"));
|
||||
assertThat(InternalAnnotationUtils.getAttributeAliasNames(location1), containsInAnyOrder("xmlFile", "groovyScript", "value", "location2", "location3"));
|
||||
assertThat(InternalAnnotationUtils.getAttributeAliasNames(location2), containsInAnyOrder("xmlFile", "groovyScript", "value", "location1", "location3"));
|
||||
assertThat(InternalAnnotationUtils.getAttributeAliasNames(location3), containsInAnyOrder("xmlFile", "groovyScript", "value", "location1", "location2"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getAttributeAliasNamesFromComposedAnnotationWithImplicitAliasesForAliasPair() throws Exception {
|
||||
Method xmlFile = ImplicitAliasesForAliasPairContextConfig.class.getDeclaredMethod("xmlFile");
|
||||
Method groovyScript = ImplicitAliasesForAliasPairContextConfig.class.getDeclaredMethod("groovyScript");
|
||||
|
||||
// Meta-annotation attribute overrides
|
||||
assertEquals("location", InternalAnnotationUtils.getAttributeOverrideName(xmlFile, ContextConfig.class));
|
||||
assertEquals("value", InternalAnnotationUtils.getAttributeOverrideName(groovyScript, ContextConfig.class));
|
||||
|
||||
// Implicit aliases
|
||||
assertThat(InternalAnnotationUtils.getAttributeAliasNames(xmlFile), containsInAnyOrder("groovyScript"));
|
||||
assertThat(InternalAnnotationUtils.getAttributeAliasNames(groovyScript), containsInAnyOrder("xmlFile"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getAttributeAliasNamesFromComposedAnnotationWithImplicitAliasesWithImpliedAliasNamesOmitted()
|
||||
throws Exception {
|
||||
|
||||
Method value = ImplicitAliasesWithImpliedAliasNamesOmittedContextConfig.class.getDeclaredMethod("value");
|
||||
Method location = ImplicitAliasesWithImpliedAliasNamesOmittedContextConfig.class.getDeclaredMethod("location");
|
||||
Method xmlFile = ImplicitAliasesWithImpliedAliasNamesOmittedContextConfig.class.getDeclaredMethod("xmlFile");
|
||||
|
||||
// Meta-annotation attribute overrides
|
||||
assertEquals("value", InternalAnnotationUtils.getAttributeOverrideName(value, ContextConfig.class));
|
||||
assertEquals("location", InternalAnnotationUtils.getAttributeOverrideName(location, ContextConfig.class));
|
||||
assertEquals("location", InternalAnnotationUtils.getAttributeOverrideName(xmlFile, ContextConfig.class));
|
||||
|
||||
// Implicit aliases
|
||||
assertThat(InternalAnnotationUtils.getAttributeAliasNames(value), containsInAnyOrder("location", "xmlFile"));
|
||||
assertThat(InternalAnnotationUtils.getAttributeAliasNames(location), containsInAnyOrder("value", "xmlFile"));
|
||||
assertThat(InternalAnnotationUtils.getAttributeAliasNames(xmlFile), containsInAnyOrder("value", "location"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getAttributeAliasNamesFromComposedAnnotationWithTransitiveImplicitAliases() throws Exception {
|
||||
Method xml = TransitiveImplicitAliasesContextConfig.class.getDeclaredMethod("xml");
|
||||
Method groovy = TransitiveImplicitAliasesContextConfig.class.getDeclaredMethod("groovy");
|
||||
|
||||
// Explicit meta-annotation attribute overrides
|
||||
assertEquals("xmlFile", InternalAnnotationUtils.getAttributeOverrideName(xml, ImplicitAliasesContextConfig.class));
|
||||
assertEquals("groovyScript", InternalAnnotationUtils.getAttributeOverrideName(groovy, ImplicitAliasesContextConfig.class));
|
||||
|
||||
// Transitive meta-annotation attribute overrides
|
||||
assertEquals("location", InternalAnnotationUtils.getAttributeOverrideName(xml, ContextConfig.class));
|
||||
assertEquals("location", InternalAnnotationUtils.getAttributeOverrideName(groovy, ContextConfig.class));
|
||||
|
||||
// Transitive implicit aliases
|
||||
assertThat(InternalAnnotationUtils.getAttributeAliasNames(xml), containsInAnyOrder("groovy"));
|
||||
assertThat(InternalAnnotationUtils.getAttributeAliasNames(groovy), containsInAnyOrder("xml"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getAttributeAliasNamesFromComposedAnnotationWithTransitiveImplicitAliasesForAliasPair() throws Exception {
|
||||
Method xml = TransitiveImplicitAliasesForAliasPairContextConfig.class.getDeclaredMethod("xml");
|
||||
Method groovy = TransitiveImplicitAliasesForAliasPairContextConfig.class.getDeclaredMethod("groovy");
|
||||
|
||||
// Explicit meta-annotation attribute overrides
|
||||
assertEquals("xmlFile", InternalAnnotationUtils.getAttributeOverrideName(xml, ImplicitAliasesForAliasPairContextConfig.class));
|
||||
assertEquals("groovyScript", InternalAnnotationUtils.getAttributeOverrideName(groovy, ImplicitAliasesForAliasPairContextConfig.class));
|
||||
|
||||
// Transitive implicit aliases
|
||||
assertThat(InternalAnnotationUtils.getAttributeAliasNames(xml), containsInAnyOrder("groovy"));
|
||||
assertThat(InternalAnnotationUtils.getAttributeAliasNames(groovy), containsInAnyOrder("xml"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getAttributeAliasNamesFromComposedAnnotationWithTransitiveImplicitAliasesWithImpliedAliasNamesOmitted()
|
||||
throws Exception {
|
||||
|
||||
Method xml = TransitiveImplicitAliasesWithImpliedAliasNamesOmittedContextConfig.class.getDeclaredMethod("xml");
|
||||
Method groovy = TransitiveImplicitAliasesWithImpliedAliasNamesOmittedContextConfig.class.getDeclaredMethod("groovy");
|
||||
|
||||
// Meta-annotation attribute overrides
|
||||
assertEquals("location", InternalAnnotationUtils.getAttributeOverrideName(xml, ContextConfig.class));
|
||||
assertEquals("location", InternalAnnotationUtils.getAttributeOverrideName(groovy, ContextConfig.class));
|
||||
|
||||
// Explicit meta-annotation attribute overrides
|
||||
assertEquals("xmlFile", InternalAnnotationUtils.getAttributeOverrideName(xml, ImplicitAliasesWithImpliedAliasNamesOmittedContextConfig.class));
|
||||
assertEquals("location", InternalAnnotationUtils.getAttributeOverrideName(groovy, ImplicitAliasesWithImpliedAliasNamesOmittedContextConfig.class));
|
||||
|
||||
// Transitive implicit aliases
|
||||
assertThat(InternalAnnotationUtils.getAttributeAliasNames(groovy), containsInAnyOrder("xml"));
|
||||
assertThat(InternalAnnotationUtils.getAttributeAliasNames(xml), containsInAnyOrder("groovy"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void synthesizeAnnotationWithoutAttributeAliases() throws Exception {
|
||||
Component component = WebController.class.getAnnotation(Component.class);
|
||||
assertNotNull(component);
|
||||
Component synthesizedComponent = InternalAnnotationUtils.synthesizeAnnotation(component);
|
||||
assertNotNull(synthesizedComponent);
|
||||
assertSame(component, synthesizedComponent);
|
||||
assertEquals("value attribute: ", "webController", synthesizedComponent.value());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void synthesizeAlreadySynthesizedAnnotation() throws Exception {
|
||||
Method method = WebController.class.getMethod("handleMappedWithValueAttribute");
|
||||
WebMapping webMapping = method.getAnnotation(WebMapping.class);
|
||||
assertNotNull(webMapping);
|
||||
WebMapping synthesizedWebMapping = InternalAnnotationUtils.synthesizeAnnotation(webMapping);
|
||||
assertNotSame(webMapping, synthesizedWebMapping);
|
||||
WebMapping synthesizedAgainWebMapping = InternalAnnotationUtils.synthesizeAnnotation(synthesizedWebMapping);
|
||||
assertThat(synthesizedAgainWebMapping, instanceOf(SynthesizedAnnotation.class));
|
||||
assertSame(synthesizedWebMapping, synthesizedAgainWebMapping);
|
||||
|
||||
assertEquals("name attribute: ", "foo", synthesizedAgainWebMapping.name());
|
||||
assertArrayEquals("aliased path attribute: ", asArray("/test"), synthesizedAgainWebMapping.path());
|
||||
assertArrayEquals("actual value attribute: ", asArray("/test"), synthesizedAgainWebMapping.value());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void synthesizeAnnotationWhereAliasForIsMissingAttributeDeclaration() throws Exception {
|
||||
AliasForWithMissingAttributeDeclaration annotation = AliasForWithMissingAttributeDeclarationClass.class.getAnnotation(AliasForWithMissingAttributeDeclaration.class);
|
||||
exception.expect(AnnotationConfigurationException.class);
|
||||
exception.expectMessage(startsWith("@AliasFor declaration on attribute 'foo' in annotation"));
|
||||
exception.expectMessage(containsString(AliasForWithMissingAttributeDeclaration.class.getName()));
|
||||
exception.expectMessage(containsString("points to itself"));
|
||||
InternalAnnotationUtils.synthesizeAnnotation(annotation);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void synthesizeAnnotationWhereAliasForHasDuplicateAttributeDeclaration() throws Exception {
|
||||
AliasForWithDuplicateAttributeDeclaration annotation = AliasForWithDuplicateAttributeDeclarationClass.class.getAnnotation(AliasForWithDuplicateAttributeDeclaration.class);
|
||||
exception.expect(AnnotationConfigurationException.class);
|
||||
exception.expectMessage(startsWith("In @AliasFor declared on attribute 'foo' in annotation"));
|
||||
exception.expectMessage(containsString(AliasForWithDuplicateAttributeDeclaration.class.getName()));
|
||||
exception.expectMessage(anyOf(
|
||||
containsString("attribute 'attribute' and its alias 'value' are present with values of [baz] and [bar]"),
|
||||
containsString("attribute 'attribute' and its alias 'value' are present with values of 'bar' and 'baz'")));
|
||||
InternalAnnotationUtils.synthesizeAnnotation(annotation);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void synthesizeAnnotationWithAttributeAliasForNonexistentAttribute() throws Exception {
|
||||
AliasForNonexistentAttribute annotation = AliasForNonexistentAttributeClass.class.getAnnotation(AliasForNonexistentAttribute.class);
|
||||
exception.expect(AnnotationConfigurationException.class);
|
||||
exception.expectMessage(either(allOf(
|
||||
startsWith("Attribute 'foo' in"),
|
||||
containsString(AliasForNonexistentAttribute.class.getName()),
|
||||
containsString("is declared as an @AliasFor nonexistent attribute 'bar'"))
|
||||
).or(
|
||||
containsString("@AliasFor declaration on attribute 'foo' in annotation ["
|
||||
+ AliasForNonexistentAttribute.class.getName()
|
||||
+ "] declares an alias for 'bar' which is not present")));
|
||||
InternalAnnotationUtils.synthesizeAnnotation(annotation);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void synthesizeAnnotationWithAttributeAliasWithoutMirroredAliasFor() throws Exception {
|
||||
AliasForWithoutMirroredAliasFor annotation =
|
||||
AliasForWithoutMirroredAliasForClass.class.getAnnotation(AliasForWithoutMirroredAliasFor.class);
|
||||
exception.expect(AnnotationConfigurationException.class);
|
||||
exception.expectMessage(allOf(startsWith("Attribute 'bar' in"),
|
||||
containsString(AliasForWithoutMirroredAliasFor.class.getName()),
|
||||
either(containsString("@AliasFor [foo]")).or(containsString("@AliasFor 'foo'"))));
|
||||
InternalAnnotationUtils.synthesizeAnnotation(annotation);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void synthesizeAnnotationWithAttributeAliasWithMirroredAliasForWrongAttribute() throws Exception {
|
||||
AliasForWithMirroredAliasForWrongAttribute annotation =
|
||||
AliasForWithMirroredAliasForWrongAttributeClass.class.getAnnotation(AliasForWithMirroredAliasForWrongAttribute.class);
|
||||
exception.expect(AnnotationConfigurationException.class);
|
||||
exception.expectMessage(startsWith("Attribute 'bar' in"));
|
||||
exception.expectMessage(containsString(AliasForWithMirroredAliasForWrongAttribute.class.getName()));
|
||||
exception.expectMessage(anyOf(
|
||||
containsString("must be declared as an @AliasFor [foo], not [quux]"),
|
||||
containsString("is declared as an @AliasFor nonexistent attribute 'quux'"),
|
||||
containsString("must be declared as an @AliasFor 'foo', not attribute 'quux'")));
|
||||
InternalAnnotationUtils.synthesizeAnnotation(annotation);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void synthesizeAnnotationWithAttributeAliasForAttributeOfDifferentType() throws Exception {
|
||||
AliasForAttributeOfDifferentType annotation =
|
||||
AliasForAttributeOfDifferentTypeClass.class.getAnnotation(AliasForAttributeOfDifferentType.class);
|
||||
exception.expect(AnnotationConfigurationException.class);
|
||||
exception.expectMessage(startsWith("Misconfigured aliases"));
|
||||
exception.expectMessage(containsString(AliasForAttributeOfDifferentType.class.getName()));
|
||||
exception.expectMessage(containsString("attribute 'foo'"));
|
||||
exception.expectMessage(containsString("attribute 'bar'"));
|
||||
exception.expectMessage(containsString("same return type"));
|
||||
InternalAnnotationUtils.synthesizeAnnotation(annotation);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void synthesizeAnnotationWithAttributeAliasForWithMissingDefaultValues() throws Exception {
|
||||
AliasForWithMissingDefaultValues annotation =
|
||||
AliasForWithMissingDefaultValuesClass.class.getAnnotation(AliasForWithMissingDefaultValues.class);
|
||||
exception.expect(AnnotationConfigurationException.class);
|
||||
exception.expectMessage(startsWith("Misconfigured aliases"));
|
||||
exception.expectMessage(containsString(AliasForWithMissingDefaultValues.class.getName()));
|
||||
exception.expectMessage(containsString("attribute 'foo' in annotation"));
|
||||
exception.expectMessage(containsString("attribute 'bar' in annotation"));
|
||||
exception.expectMessage(containsString("default values"));
|
||||
InternalAnnotationUtils.synthesizeAnnotation(annotation);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void synthesizeAnnotationWithAttributeAliasForAttributeWithDifferentDefaultValue() throws Exception {
|
||||
AliasForAttributeWithDifferentDefaultValue annotation =
|
||||
AliasForAttributeWithDifferentDefaultValueClass.class.getAnnotation(AliasForAttributeWithDifferentDefaultValue.class);
|
||||
exception.expect(AnnotationConfigurationException.class);
|
||||
exception.expectMessage(startsWith("Misconfigured aliases"));
|
||||
exception.expectMessage(containsString(AliasForAttributeWithDifferentDefaultValue.class.getName()));
|
||||
exception.expectMessage(containsString("attribute 'foo' in annotation"));
|
||||
exception.expectMessage(containsString("attribute 'bar' in annotation"));
|
||||
exception.expectMessage(containsString("same default value"));
|
||||
InternalAnnotationUtils.synthesizeAnnotation(annotation);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void synthesizeAnnotationWithAttributeAliasForMetaAnnotationThatIsNotMetaPresent() throws Exception {
|
||||
AliasedComposedContextConfigNotMetaPresent annotation =
|
||||
AliasedComposedContextConfigNotMetaPresentClass.class.getAnnotation(AliasedComposedContextConfigNotMetaPresent.class);
|
||||
exception.expect(AnnotationConfigurationException.class);
|
||||
exception.expectMessage(startsWith("@AliasFor declaration on attribute 'xmlConfigFile' in annotation"));
|
||||
exception.expectMessage(containsString(AliasedComposedContextConfigNotMetaPresent.class.getName()));
|
||||
exception.expectMessage(containsString("declares an alias for attribute 'location'"));
|
||||
exception.expectMessage(containsString(ContextConfig.class.getName()));
|
||||
exception.expectMessage(containsString("not meta-present"));
|
||||
InternalAnnotationUtils.synthesizeAnnotation(annotation);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void synthesizeAnnotationWithAttributeAliases() throws Exception {
|
||||
Method method = WebController.class.getMethod("handleMappedWithValueAttribute");
|
||||
WebMapping webMapping = method.getAnnotation(WebMapping.class);
|
||||
assertNotNull(webMapping);
|
||||
|
||||
WebMapping synthesizedWebMapping1 = InternalAnnotationUtils.synthesizeAnnotation(webMapping);
|
||||
assertThat(synthesizedWebMapping1, instanceOf(SynthesizedAnnotation.class));
|
||||
assertNotSame(webMapping, synthesizedWebMapping1);
|
||||
|
||||
assertEquals("name attribute: ", "foo", synthesizedWebMapping1.name());
|
||||
assertArrayEquals("aliased path attribute: ", asArray("/test"), synthesizedWebMapping1.path());
|
||||
assertArrayEquals("actual value attribute: ", asArray("/test"), synthesizedWebMapping1.value());
|
||||
|
||||
WebMapping synthesizedWebMapping2 = InternalAnnotationUtils.synthesizeAnnotation(webMapping);
|
||||
assertThat(synthesizedWebMapping2, instanceOf(SynthesizedAnnotation.class));
|
||||
assertNotSame(webMapping, synthesizedWebMapping2);
|
||||
|
||||
assertEquals("name attribute: ", "foo", synthesizedWebMapping2.name());
|
||||
assertArrayEquals("aliased path attribute: ", asArray("/test"), synthesizedWebMapping2.path());
|
||||
assertArrayEquals("actual value attribute: ", asArray("/test"), synthesizedWebMapping2.value());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void synthesizeAnnotationWithImplicitAliases() throws Exception {
|
||||
assertAnnotationSynthesisWithImplicitAliases(ValueImplicitAliasesContextConfigClass.class, "value");
|
||||
assertAnnotationSynthesisWithImplicitAliases(Location1ImplicitAliasesContextConfigClass.class, "location1");
|
||||
assertAnnotationSynthesisWithImplicitAliases(XmlImplicitAliasesContextConfigClass.class, "xmlFile");
|
||||
assertAnnotationSynthesisWithImplicitAliases(GroovyImplicitAliasesContextConfigClass.class, "groovyScript");
|
||||
}
|
||||
|
||||
private void assertAnnotationSynthesisWithImplicitAliases(Class<?> clazz, String expected) throws Exception {
|
||||
ImplicitAliasesContextConfig config = clazz.getAnnotation(ImplicitAliasesContextConfig.class);
|
||||
assertNotNull(config);
|
||||
|
||||
ImplicitAliasesContextConfig synthesizedConfig = InternalAnnotationUtils.synthesizeAnnotation(config);
|
||||
assertThat(synthesizedConfig, instanceOf(SynthesizedAnnotation.class));
|
||||
|
||||
assertEquals("value: ", expected, synthesizedConfig.value());
|
||||
assertEquals("location1: ", expected, synthesizedConfig.location1());
|
||||
assertEquals("xmlFile: ", expected, synthesizedConfig.xmlFile());
|
||||
assertEquals("groovyScript: ", expected, synthesizedConfig.groovyScript());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void synthesizeAnnotationWithImplicitAliasesWithImpliedAliasNamesOmitted() throws Exception {
|
||||
assertAnnotationSynthesisWithImplicitAliasesWithImpliedAliasNamesOmitted(
|
||||
ValueImplicitAliasesWithImpliedAliasNamesOmittedContextConfigClass.class, "value");
|
||||
assertAnnotationSynthesisWithImplicitAliasesWithImpliedAliasNamesOmitted(
|
||||
LocationsImplicitAliasesWithImpliedAliasNamesOmittedContextConfigClass.class, "location");
|
||||
assertAnnotationSynthesisWithImplicitAliasesWithImpliedAliasNamesOmitted(
|
||||
XmlFilesImplicitAliasesWithImpliedAliasNamesOmittedContextConfigClass.class, "xmlFile");
|
||||
}
|
||||
|
||||
private void assertAnnotationSynthesisWithImplicitAliasesWithImpliedAliasNamesOmitted(
|
||||
Class<?> clazz, String expected) {
|
||||
|
||||
ImplicitAliasesWithImpliedAliasNamesOmittedContextConfig config = clazz.getAnnotation(
|
||||
ImplicitAliasesWithImpliedAliasNamesOmittedContextConfig.class);
|
||||
assertNotNull(config);
|
||||
|
||||
ImplicitAliasesWithImpliedAliasNamesOmittedContextConfig synthesizedConfig = InternalAnnotationUtils.synthesizeAnnotation(config);
|
||||
assertThat(synthesizedConfig, instanceOf(SynthesizedAnnotation.class));
|
||||
|
||||
assertEquals("value: ", expected, synthesizedConfig.value());
|
||||
assertEquals("locations: ", expected, synthesizedConfig.location());
|
||||
assertEquals("xmlFiles: ", expected, synthesizedConfig.xmlFile());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void synthesizeAnnotationWithImplicitAliasesForAliasPair() throws Exception {
|
||||
Class<?> clazz = ImplicitAliasesForAliasPairContextConfigClass.class;
|
||||
ImplicitAliasesForAliasPairContextConfig config = clazz.getAnnotation(ImplicitAliasesForAliasPairContextConfig.class);
|
||||
assertNotNull(config);
|
||||
|
||||
ImplicitAliasesForAliasPairContextConfig synthesizedConfig = InternalAnnotationUtils.synthesizeAnnotation(config);
|
||||
assertThat(synthesizedConfig, instanceOf(SynthesizedAnnotation.class));
|
||||
|
||||
assertEquals("xmlFile: ", "test.xml", synthesizedConfig.xmlFile());
|
||||
assertEquals("groovyScript: ", "test.xml", synthesizedConfig.groovyScript());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void synthesizeAnnotationWithTransitiveImplicitAliases() throws Exception {
|
||||
Class<?> clazz = TransitiveImplicitAliasesContextConfigClass.class;
|
||||
TransitiveImplicitAliasesContextConfig config = clazz.getAnnotation(TransitiveImplicitAliasesContextConfig.class);
|
||||
assertNotNull(config);
|
||||
|
||||
TransitiveImplicitAliasesContextConfig synthesizedConfig = InternalAnnotationUtils.synthesizeAnnotation(config);
|
||||
assertThat(synthesizedConfig, instanceOf(SynthesizedAnnotation.class));
|
||||
|
||||
assertEquals("xml: ", "test.xml", synthesizedConfig.xml());
|
||||
assertEquals("groovy: ", "test.xml", synthesizedConfig.groovy());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void synthesizeAnnotationWithTransitiveImplicitAliasesForAliasPair() throws Exception {
|
||||
Class<?> clazz = TransitiveImplicitAliasesForAliasPairContextConfigClass.class;
|
||||
TransitiveImplicitAliasesForAliasPairContextConfig config = clazz.getAnnotation(TransitiveImplicitAliasesForAliasPairContextConfig.class);
|
||||
assertNotNull(config);
|
||||
|
||||
TransitiveImplicitAliasesForAliasPairContextConfig synthesizedConfig = InternalAnnotationUtils.synthesizeAnnotation(config);
|
||||
assertThat(synthesizedConfig, instanceOf(SynthesizedAnnotation.class));
|
||||
|
||||
assertEquals("xml: ", "test.xml", synthesizedConfig.xml());
|
||||
assertEquals("groovy: ", "test.xml", synthesizedConfig.groovy());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void synthesizeAnnotationWithImplicitAliasesWithMissingDefaultValues() throws Exception {
|
||||
Class<?> clazz = ImplicitAliasesWithMissingDefaultValuesContextConfigClass.class;
|
||||
@@ -1245,13 +869,6 @@ public class AnnotationUtilsTests {
|
||||
assertEquals("location: ", "", contextConfig.location());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void synthesizeAnnotationWithAttributeAliasesWithDifferentValues() throws Exception {
|
||||
exception.expect(AnnotationConfigurationException.class);
|
||||
ContextConfig contextConfig = InternalAnnotationUtils.synthesizeAnnotation(ContextConfigMismatch.class.getAnnotation(ContextConfig.class));
|
||||
getValue(contextConfig);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void synthesizeAnnotationFromMapWithMinimalAttributesWithAttributeAliases() throws Exception {
|
||||
Map<String, Object> map = Collections.singletonMap("location", "test.xml");
|
||||
@@ -1325,16 +942,9 @@ public class AnnotationUtilsTests {
|
||||
public void synthesizeAnnotationFromMapWithAttributeOfIncorrectType() throws Exception {
|
||||
Map<String, Object> map = Collections.singletonMap(VALUE, 42L);
|
||||
exception.expect(IllegalArgumentException.class);
|
||||
exception.expectMessage(either(allOf(startsWith("Attributes map"),
|
||||
containsString("returned a value of type [java.lang.Long]"),
|
||||
containsString("for attribute 'value'"),
|
||||
containsString("but a value of type [java.lang.String] is required"),
|
||||
containsString("as defined by annotation type ["
|
||||
+ Component.class.getName() + "]"))).or(
|
||||
containsString("Attribute 'value' in annotation "
|
||||
+ Component.class.getName()
|
||||
+ " should be of type "
|
||||
+ "java.lang.String but a java.lang.Long value was returned")));
|
||||
exception.expectMessage(containsString(
|
||||
"Attribute 'value' in annotation org.springframework.stereotype.Component "
|
||||
+ "should be compatible with java.lang.String but a java.lang.Long value was returned"));
|
||||
synthesizeAnnotation(map, Component.class, null);
|
||||
}
|
||||
|
||||
@@ -1359,210 +969,6 @@ public class AnnotationUtilsTests {
|
||||
assertEquals("value from synthesized component: ", "webController", synthesizedComponent.value());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void toStringForSynthesizedAnnotations() throws Exception {
|
||||
Method methodWithPath = WebController.class.getMethod("handleMappedWithPathAttribute");
|
||||
WebMapping webMappingWithAliases = methodWithPath.getAnnotation(WebMapping.class);
|
||||
assertNotNull(webMappingWithAliases);
|
||||
|
||||
Method methodWithPathAndValue = WebController.class.getMethod("handleMappedWithSamePathAndValueAttributes");
|
||||
WebMapping webMappingWithPathAndValue = methodWithPathAndValue.getAnnotation(WebMapping.class);
|
||||
assertNotNull(webMappingWithPathAndValue);
|
||||
|
||||
WebMapping synthesizedWebMapping1 = InternalAnnotationUtils.synthesizeAnnotation(webMappingWithAliases);
|
||||
assertNotNull(synthesizedWebMapping1);
|
||||
WebMapping synthesizedWebMapping2 = InternalAnnotationUtils.synthesizeAnnotation(webMappingWithAliases);
|
||||
assertNotNull(synthesizedWebMapping2);
|
||||
|
||||
assertThat(webMappingWithAliases.toString(), is(not(synthesizedWebMapping1.toString())));
|
||||
assertToStringForWebMappingWithPathAndValue(synthesizedWebMapping1);
|
||||
assertToStringForWebMappingWithPathAndValue(synthesizedWebMapping2);
|
||||
}
|
||||
|
||||
private void assertToStringForWebMappingWithPathAndValue(WebMapping webMapping) {
|
||||
String string = webMapping.toString();
|
||||
assertThat(string, startsWith("@" + WebMapping.class.getName() + "("));
|
||||
assertThat(string, containsString("value=[/test]"));
|
||||
assertThat(string, containsString("path=[/test]"));
|
||||
assertThat(string, containsString("name=bar"));
|
||||
assertThat(string, containsString("method="));
|
||||
assertThat(string, containsString("[GET, POST]"));
|
||||
assertThat(string, endsWith(")"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void equalsForSynthesizedAnnotations() throws Exception {
|
||||
Method methodWithPath = WebController.class.getMethod("handleMappedWithPathAttribute");
|
||||
WebMapping webMappingWithAliases = methodWithPath.getAnnotation(WebMapping.class);
|
||||
assertNotNull(webMappingWithAliases);
|
||||
|
||||
Method methodWithPathAndValue = WebController.class.getMethod("handleMappedWithSamePathAndValueAttributes");
|
||||
WebMapping webMappingWithPathAndValue = methodWithPathAndValue.getAnnotation(WebMapping.class);
|
||||
assertNotNull(webMappingWithPathAndValue);
|
||||
|
||||
WebMapping synthesizedWebMapping1 = InternalAnnotationUtils.synthesizeAnnotation(webMappingWithAliases);
|
||||
assertNotNull(synthesizedWebMapping1);
|
||||
WebMapping synthesizedWebMapping2 = InternalAnnotationUtils.synthesizeAnnotation(webMappingWithAliases);
|
||||
assertNotNull(synthesizedWebMapping2);
|
||||
|
||||
// Equality amongst standard annotations
|
||||
assertThat(webMappingWithAliases, is(webMappingWithAliases));
|
||||
assertThat(webMappingWithPathAndValue, is(webMappingWithPathAndValue));
|
||||
|
||||
// Inequality amongst standard annotations
|
||||
assertThat(webMappingWithAliases, is(not(webMappingWithPathAndValue)));
|
||||
assertThat(webMappingWithPathAndValue, is(not(webMappingWithAliases)));
|
||||
|
||||
// Equality amongst synthesized annotations
|
||||
assertThat(synthesizedWebMapping1, is(synthesizedWebMapping1));
|
||||
assertThat(synthesizedWebMapping2, is(synthesizedWebMapping2));
|
||||
assertThat(synthesizedWebMapping1, is(synthesizedWebMapping2));
|
||||
assertThat(synthesizedWebMapping2, is(synthesizedWebMapping1));
|
||||
|
||||
// Equality between standard and synthesized annotations
|
||||
assertThat(synthesizedWebMapping1, is(webMappingWithPathAndValue));
|
||||
assertThat(webMappingWithPathAndValue, is(synthesizedWebMapping1));
|
||||
|
||||
// Inequality between standard and synthesized annotations
|
||||
assertThat(synthesizedWebMapping1, is(not(webMappingWithAliases)));
|
||||
assertThat(webMappingWithAliases, is(not(synthesizedWebMapping1)));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void hashCodeForSynthesizedAnnotations() throws Exception {
|
||||
Method methodWithPath = WebController.class.getMethod("handleMappedWithPathAttribute");
|
||||
WebMapping webMappingWithAliases = methodWithPath.getAnnotation(WebMapping.class);
|
||||
assertNotNull(webMappingWithAliases);
|
||||
|
||||
Method methodWithPathAndValue = WebController.class.getMethod("handleMappedWithSamePathAndValueAttributes");
|
||||
WebMapping webMappingWithPathAndValue = methodWithPathAndValue.getAnnotation(WebMapping.class);
|
||||
assertNotNull(webMappingWithPathAndValue);
|
||||
|
||||
WebMapping synthesizedWebMapping1 = InternalAnnotationUtils.synthesizeAnnotation(webMappingWithAliases);
|
||||
assertNotNull(synthesizedWebMapping1);
|
||||
WebMapping synthesizedWebMapping2 = InternalAnnotationUtils.synthesizeAnnotation(webMappingWithAliases);
|
||||
assertNotNull(synthesizedWebMapping2);
|
||||
|
||||
// Equality amongst standard annotations
|
||||
assertThat(webMappingWithAliases.hashCode(), is(webMappingWithAliases.hashCode()));
|
||||
assertThat(webMappingWithPathAndValue.hashCode(), is(webMappingWithPathAndValue.hashCode()));
|
||||
|
||||
// Inequality amongst standard annotations
|
||||
assertThat(webMappingWithAliases.hashCode(), is(not(webMappingWithPathAndValue.hashCode())));
|
||||
assertThat(webMappingWithPathAndValue.hashCode(), is(not(webMappingWithAliases.hashCode())));
|
||||
|
||||
// Equality amongst synthesized annotations
|
||||
assertThat(synthesizedWebMapping1.hashCode(), is(synthesizedWebMapping1.hashCode()));
|
||||
assertThat(synthesizedWebMapping2.hashCode(), is(synthesizedWebMapping2.hashCode()));
|
||||
assertThat(synthesizedWebMapping1.hashCode(), is(synthesizedWebMapping2.hashCode()));
|
||||
assertThat(synthesizedWebMapping2.hashCode(), is(synthesizedWebMapping1.hashCode()));
|
||||
|
||||
// Equality between standard and synthesized annotations
|
||||
assertThat(synthesizedWebMapping1.hashCode(), is(webMappingWithPathAndValue.hashCode()));
|
||||
assertThat(webMappingWithPathAndValue.hashCode(), is(synthesizedWebMapping1.hashCode()));
|
||||
|
||||
// Inequality between standard and synthesized annotations
|
||||
assertThat(synthesizedWebMapping1.hashCode(), is(not(webMappingWithAliases.hashCode())));
|
||||
assertThat(webMappingWithAliases.hashCode(), is(not(synthesizedWebMapping1.hashCode())));
|
||||
}
|
||||
|
||||
/**
|
||||
* Fully reflection-based test that verifies support for
|
||||
* {@linkplain AnnotationUtils#synthesizeAnnotation synthesizing annotations}
|
||||
* across packages with non-public visibility of user types (e.g., a non-public
|
||||
* annotation that uses {@code @AliasFor}).
|
||||
*/
|
||||
@Test
|
||||
@SuppressWarnings("unchecked")
|
||||
public void synthesizeNonPublicAnnotationWithAttributeAliasesFromDifferentPackage() throws Exception {
|
||||
Class<?> clazz =
|
||||
ClassUtils.forName("org.springframework.core.annotation.subpackage.NonPublicAliasedAnnotatedClass", null);
|
||||
Class<? extends Annotation> annotationType = (Class<? extends Annotation>)
|
||||
ClassUtils.forName("org.springframework.core.annotation.subpackage.NonPublicAliasedAnnotation", null);
|
||||
|
||||
Annotation annotation = clazz.getAnnotation(annotationType);
|
||||
assertNotNull(annotation);
|
||||
Annotation synthesizedAnnotation = InternalAnnotationUtils.synthesizeAnnotation(annotation);
|
||||
assertNotSame(annotation, synthesizedAnnotation);
|
||||
|
||||
assertNotNull(synthesizedAnnotation);
|
||||
assertEquals("name attribute: ", "test", getValue(synthesizedAnnotation, "name"));
|
||||
assertEquals("aliased path attribute: ", "/test", getValue(synthesizedAnnotation, "path"));
|
||||
assertEquals("aliased path attribute: ", "/test", getValue(synthesizedAnnotation, "value"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void synthesizeAnnotationWithAttributeAliasesInNestedAnnotations() throws Exception {
|
||||
List<String> expectedLocations = asList("A", "B");
|
||||
|
||||
Hierarchy hierarchy = ConfigHierarchyTestCase.class.getAnnotation(Hierarchy.class);
|
||||
assertNotNull(hierarchy);
|
||||
Hierarchy synthesizedHierarchy = InternalAnnotationUtils.synthesizeAnnotation(hierarchy);
|
||||
assertNotSame(hierarchy, synthesizedHierarchy);
|
||||
assertThat(synthesizedHierarchy, instanceOf(SynthesizedAnnotation.class));
|
||||
|
||||
ContextConfig[] configs = synthesizedHierarchy.value();
|
||||
assertNotNull(configs);
|
||||
assertTrue("nested annotations must be synthesized",
|
||||
stream(configs).allMatch(c -> c instanceof SynthesizedAnnotation));
|
||||
|
||||
List<String> locations = stream(configs).map(ContextConfig::location).collect(toList());
|
||||
assertThat(locations, is(expectedLocations));
|
||||
|
||||
List<String> values = stream(configs).map(ContextConfig::value).collect(toList());
|
||||
assertThat(values, is(expectedLocations));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void synthesizeAnnotationWithArrayOfAnnotations() throws Exception {
|
||||
List<String> expectedLocations = asList("A", "B");
|
||||
|
||||
Hierarchy hierarchy = ConfigHierarchyTestCase.class.getAnnotation(Hierarchy.class);
|
||||
assertNotNull(hierarchy);
|
||||
Hierarchy synthesizedHierarchy = InternalAnnotationUtils.synthesizeAnnotation(hierarchy);
|
||||
assertThat(synthesizedHierarchy, instanceOf(SynthesizedAnnotation.class));
|
||||
|
||||
ContextConfig contextConfig = SimpleConfigTestCase.class.getAnnotation(ContextConfig.class);
|
||||
assertNotNull(contextConfig);
|
||||
|
||||
ContextConfig[] configs = synthesizedHierarchy.value();
|
||||
List<String> locations = stream(configs).map(ContextConfig::location).collect(toList());
|
||||
assertThat(locations, is(expectedLocations));
|
||||
|
||||
// Alter array returned from synthesized annotation
|
||||
configs[0] = contextConfig;
|
||||
|
||||
// Re-retrieve the array from the synthesized annotation
|
||||
configs = synthesizedHierarchy.value();
|
||||
List<String> values = stream(configs).map(ContextConfig::value).collect(toList());
|
||||
assertThat(values, is(expectedLocations));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void synthesizeAnnotationWithArrayOfChars() throws Exception {
|
||||
CharsContainer charsContainer = GroupOfCharsClass.class.getAnnotation(CharsContainer.class);
|
||||
assertNotNull(charsContainer);
|
||||
CharsContainer synthesizedCharsContainer = InternalAnnotationUtils.synthesizeAnnotation(charsContainer);
|
||||
assertThat(synthesizedCharsContainer, instanceOf(SynthesizedAnnotation.class));
|
||||
|
||||
char[] chars = synthesizedCharsContainer.chars();
|
||||
assertArrayEquals(new char[] { 'x', 'y', 'z' }, chars);
|
||||
|
||||
// Alter array returned from synthesized annotation
|
||||
chars[0] = '?';
|
||||
|
||||
// Re-retrieve the array from the synthesized annotation
|
||||
chars = synthesizedCharsContainer.chars();
|
||||
assertArrayEquals(new char[] { 'x', 'y', 'z' }, chars);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void interfaceWithAnnotatedMethods() {
|
||||
assertTrue(InternalAnnotationUtils.getAnnotatedMethodsInBaseType(NonAnnotatedInterface.class).isEmpty());
|
||||
assertFalse(InternalAnnotationUtils.getAnnotatedMethodsInBaseType(AnnotatedInterface.class).isEmpty());
|
||||
assertTrue(InternalAnnotationUtils.getAnnotatedMethodsInBaseType(NullableAnnotatedInterface.class).isEmpty());
|
||||
}
|
||||
|
||||
|
||||
@SafeVarargs
|
||||
static <T> T[] asArray(T... arr) {
|
||||
|
||||
@@ -1,34 +0,0 @@
|
||||
/*
|
||||
* Copyright 2002-2015 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.core.annotation;
|
||||
|
||||
import java.lang.annotation.Annotation;
|
||||
|
||||
/**
|
||||
* Unit tests for {@link DefaultAnnotationAttributeExtractor}.
|
||||
*
|
||||
* @author Sam Brannen
|
||||
* @since 4.2.1
|
||||
*/
|
||||
public class DefaultAnnotationAttributeExtractorTests extends AbstractAliasAwareAnnotationAttributeExtractorTestCase {
|
||||
|
||||
@Override
|
||||
protected AnnotationAttributeExtractor<?> createExtractorFor(Class<?> clazz, String expected, Class<? extends Annotation> annotationType) {
|
||||
return new DefaultAnnotationAttributeExtractor(clazz.getAnnotation(annotationType), clazz);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,149 +0,0 @@
|
||||
/*
|
||||
* Copyright 2002-2019 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.core.annotation;
|
||||
|
||||
import java.lang.annotation.Annotation;
|
||||
import java.lang.reflect.Field;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
|
||||
import org.springframework.util.LinkedMultiValueMap;
|
||||
import org.springframework.util.MultiValueMap;
|
||||
|
||||
import static org.hamcrest.Matchers.*;
|
||||
import static org.junit.Assert.*;
|
||||
import static org.springframework.core.annotation.AnnotationUtilsTests.*;
|
||||
|
||||
/**
|
||||
* Unit tests for {@link MapAnnotationAttributeExtractor}.
|
||||
*
|
||||
* @author Sam Brannen
|
||||
* @since 4.2.1
|
||||
*/
|
||||
@SuppressWarnings("serial")
|
||||
public class MapAnnotationAttributeExtractorTests extends AbstractAliasAwareAnnotationAttributeExtractorTestCase {
|
||||
|
||||
@Override
|
||||
protected AnnotationAttributeExtractor<?> createExtractorFor(Class<?> clazz, String expected, Class<? extends Annotation> annotationType) {
|
||||
Map<String, Object> attributes = Collections.singletonMap(expected, expected);
|
||||
return new MapAnnotationAttributeExtractor(attributes, annotationType, clazz);
|
||||
}
|
||||
|
||||
@Before
|
||||
public void clearCacheBeforeTests() {
|
||||
AnnotationUtils.clearCache();
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void enrichAndValidateAttributesWithImplicitAliasesAndMinimalAttributes() throws Exception {
|
||||
Map<String, Object> attributes = new HashMap<>();
|
||||
Map<String, Object> expectedAttributes = new HashMap<String, Object>() {{
|
||||
put("groovyScript", "");
|
||||
put("xmlFile", "");
|
||||
put("value", "");
|
||||
put("location1", "");
|
||||
put("location2", "");
|
||||
put("location3", "");
|
||||
put("nonAliasedAttribute", "");
|
||||
put("configClass", Object.class);
|
||||
}};
|
||||
|
||||
assertEnrichAndValidateAttributes(attributes, expectedAttributes);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void enrichAndValidateAttributesWithImplicitAliases() throws Exception {
|
||||
Map<String, Object> attributes = new HashMap<String, Object>() {{
|
||||
put("groovyScript", "groovy!");
|
||||
}};
|
||||
|
||||
Map<String, Object> expectedAttributes = new HashMap<String, Object>() {{
|
||||
put("groovyScript", "groovy!");
|
||||
put("xmlFile", "groovy!");
|
||||
put("value", "groovy!");
|
||||
put("location1", "groovy!");
|
||||
put("location2", "groovy!");
|
||||
put("location3", "groovy!");
|
||||
put("nonAliasedAttribute", "");
|
||||
put("configClass", Object.class);
|
||||
}};
|
||||
|
||||
assertEnrichAndValidateAttributes(attributes, expectedAttributes);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void enrichAndValidateAttributesWithSingleElementThatOverridesAnArray() {
|
||||
Map<String, Object> attributes = new HashMap<String, Object>() {{
|
||||
// Intentionally storing 'value' as a single String instead of an array.
|
||||
// put("value", asArray("/foo"));
|
||||
put("value", "/foo");
|
||||
put("name", "test");
|
||||
}};
|
||||
|
||||
Map<String, Object> expected = new HashMap<String, Object>() {{
|
||||
put("value", asArray("/foo"));
|
||||
put("path", asArray("/foo"));
|
||||
put("name", "test");
|
||||
put("method", new RequestMethod[0]);
|
||||
}};
|
||||
|
||||
MapAnnotationAttributeExtractor extractor = new MapAnnotationAttributeExtractor(attributes, WebMapping.class, null);
|
||||
Map<String, Object> enriched = extractor.getSource();
|
||||
|
||||
assertEquals("attribute map size", expected.size(), enriched.size());
|
||||
expected.forEach((attr, expectedValue) -> assertThat("for attribute '" + attr + "'", enriched.get(attr), is(expectedValue)));
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private void assertEnrichAndValidateAttributes(Map<String, Object> sourceAttributes, Map<String, Object> expected) throws Exception {
|
||||
Class<? extends Annotation> annotationType = ImplicitAliasesContextConfig.class;
|
||||
|
||||
// Since the ordering of attribute methods returned by the JVM is non-deterministic,
|
||||
// we have to rig the attributeAliasesCache in AnnotationUtils so that the tests
|
||||
// consistently fail in case enrichAndValidateAttributes() is buggy.
|
||||
// Otherwise, these tests would intermittently pass even for an invalid implementation.
|
||||
Field cacheField = InternalAnnotationUtils.class.getDeclaredField("attributeAliasesCache");
|
||||
cacheField.setAccessible(true);
|
||||
Map<Class<? extends Annotation>, MultiValueMap<String, String>> attributeAliasesCache =
|
||||
(Map<Class<? extends Annotation>, MultiValueMap<String, String>>) cacheField.get(null);
|
||||
|
||||
// Declare aliases in an order that will cause enrichAndValidateAttributes() to
|
||||
// fail unless it considers all aliases in the set of implicit aliases.
|
||||
MultiValueMap<String, String> aliases = new LinkedMultiValueMap<>();
|
||||
aliases.put("xmlFile", Arrays.asList("value", "groovyScript", "location1", "location2", "location3"));
|
||||
aliases.put("groovyScript", Arrays.asList("value", "xmlFile", "location1", "location2", "location3"));
|
||||
aliases.put("value", Arrays.asList("xmlFile", "groovyScript", "location1", "location2", "location3"));
|
||||
aliases.put("location1", Arrays.asList("xmlFile", "groovyScript", "value", "location2", "location3"));
|
||||
aliases.put("location2", Arrays.asList("xmlFile", "groovyScript", "value", "location1", "location3"));
|
||||
aliases.put("location3", Arrays.asList("xmlFile", "groovyScript", "value", "location1", "location2"));
|
||||
|
||||
attributeAliasesCache.put(annotationType, aliases);
|
||||
|
||||
MapAnnotationAttributeExtractor extractor = new MapAnnotationAttributeExtractor(sourceAttributes, annotationType, null);
|
||||
Map<String, Object> enriched = extractor.getSource();
|
||||
|
||||
assertEquals("attribute map size", expected.size(), enriched.size());
|
||||
expected.forEach((attr, expectedValue) -> assertThat("for attribute '" + attr + "'", enriched.get(attr), is(expectedValue)));
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user