Migrate and verify annotation utility methods
Migrate all possible `AnnotationUtils` and `AnnotatedElementUtils` method to the `MergedAnnotation` API, verify results against the old implementations. All migrated methods now call both the new API and the old version and ensure that the same results or exceptions are raised. A full build of both Spring Framework and Spring Boot has been executed to ensure, as much as possible, that the migration does not cause unexpected regressions. See gh-22562
This commit is contained in:
committed by
Juergen Hoeller
parent
b91ccf038f
commit
a14bfe9a21
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2018 the original author or authors.
|
||||
* 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.
|
||||
@@ -459,7 +459,9 @@ public class AnnotatedElementUtilsTests {
|
||||
exception.expectMessage(either(
|
||||
containsString("values of [{duplicateDeclaration}] and [{requiredLocationsDeclaration}]")).or(
|
||||
containsString("values of [{requiredLocationsDeclaration}] and [{duplicateDeclaration}]")));
|
||||
exception.expectMessage(containsString("but only one is permitted"));
|
||||
exception.expectMessage(either(
|
||||
containsString("but only one is permitted")).or(
|
||||
containsString("Different @AliasFor mirror values for annotation")));
|
||||
getMergedAnnotationAttributes(element, ContextConfig.class);
|
||||
}
|
||||
|
||||
|
||||
@@ -562,7 +562,9 @@ public class AnnotationUtilsTests {
|
||||
exception.expect(AnnotationConfigurationException.class);
|
||||
exception.expectMessage(startsWith("Attribute 'value' in"));
|
||||
exception.expectMessage(containsString(BrokenContextConfig.class.getName()));
|
||||
exception.expectMessage(containsString("@AliasFor [location]"));
|
||||
exception.expectMessage(either(
|
||||
containsString("@AliasFor [location]")).or(
|
||||
containsString("@AliasFor 'location'")));
|
||||
|
||||
getRepeatableAnnotations(BrokenConfigHierarchyTestCase.class, BrokenContextConfig.class, BrokenHierarchy.class);
|
||||
}
|
||||
@@ -897,7 +899,9 @@ public class AnnotationUtilsTests {
|
||||
exception.expect(AnnotationConfigurationException.class);
|
||||
exception.expectMessage(startsWith("In @AliasFor declared on attribute 'foo' in annotation"));
|
||||
exception.expectMessage(containsString(AliasForWithDuplicateAttributeDeclaration.class.getName()));
|
||||
exception.expectMessage(containsString("attribute 'attribute' and its alias 'value' are present with values of [baz] and [bar]"));
|
||||
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);
|
||||
}
|
||||
|
||||
@@ -905,9 +909,14 @@ public class AnnotationUtilsTests {
|
||||
public void synthesizeAnnotationWithAttributeAliasForNonexistentAttribute() throws Exception {
|
||||
AliasForNonexistentAttribute annotation = AliasForNonexistentAttributeClass.class.getAnnotation(AliasForNonexistentAttribute.class);
|
||||
exception.expect(AnnotationConfigurationException.class);
|
||||
exception.expectMessage(startsWith("Attribute 'foo' in"));
|
||||
exception.expectMessage(containsString(AliasForNonexistentAttribute.class.getName()));
|
||||
exception.expectMessage(containsString("is declared as an @AliasFor nonexistent attribute 'bar'"));
|
||||
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);
|
||||
}
|
||||
|
||||
@@ -916,9 +925,9 @@ public class AnnotationUtilsTests {
|
||||
AliasForWithoutMirroredAliasFor annotation =
|
||||
AliasForWithoutMirroredAliasForClass.class.getAnnotation(AliasForWithoutMirroredAliasFor.class);
|
||||
exception.expect(AnnotationConfigurationException.class);
|
||||
exception.expectMessage(startsWith("Attribute 'bar' in"));
|
||||
exception.expectMessage(containsString(AliasForWithoutMirroredAliasFor.class.getName()));
|
||||
exception.expectMessage(containsString("@AliasFor [foo]"));
|
||||
exception.expectMessage(allOf(startsWith("Attribute 'bar' in"),
|
||||
containsString(AliasForWithoutMirroredAliasFor.class.getName()),
|
||||
either(containsString("@AliasFor [foo]")).or(containsString("@AliasFor 'foo'"))));
|
||||
InternalAnnotationUtils.synthesizeAnnotation(annotation);
|
||||
}
|
||||
|
||||
@@ -929,8 +938,10 @@ public class AnnotationUtilsTests {
|
||||
exception.expect(AnnotationConfigurationException.class);
|
||||
exception.expectMessage(startsWith("Attribute 'bar' in"));
|
||||
exception.expectMessage(containsString(AliasForWithMirroredAliasForWrongAttribute.class.getName()));
|
||||
exception.expectMessage(either(containsString("must be declared as an @AliasFor [foo], not [quux]")).
|
||||
or(containsString("is declared as an @AliasFor nonexistent attribute 'quux'")));
|
||||
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);
|
||||
}
|
||||
|
||||
@@ -980,7 +991,7 @@ public class AnnotationUtilsTests {
|
||||
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' in meta-annotation"));
|
||||
exception.expectMessage(containsString("declares an alias for attribute 'location'"));
|
||||
exception.expectMessage(containsString(ContextConfig.class.getName()));
|
||||
exception.expectMessage(containsString("not meta-present"));
|
||||
InternalAnnotationUtils.synthesizeAnnotation(annotation);
|
||||
@@ -1133,21 +1144,16 @@ public class AnnotationUtilsTests {
|
||||
ImplicitAliasesWithDuplicateValuesContextConfig config = clazz.getAnnotation(annotationType);
|
||||
assertNotNull(config);
|
||||
|
||||
ImplicitAliasesWithDuplicateValuesContextConfig synthesizedConfig = synthesizeAnnotation(config, clazz);
|
||||
assertNotNull(synthesizedConfig);
|
||||
|
||||
exception.expect(AnnotationConfigurationException.class);
|
||||
exception.expectMessage(startsWith("In annotation"));
|
||||
exception.expectMessage(either(startsWith("In annotation")).or(startsWith("Different @AliasFor mirror values")));
|
||||
exception.expectMessage(containsString(annotationType.getName()));
|
||||
exception.expectMessage(containsString("declared on class"));
|
||||
exception.expectMessage(containsString(clazz.getName()));
|
||||
exception.expectMessage(containsString("and synthesized from"));
|
||||
exception.expectMessage(either(containsString("attribute 'location1' and its alias 'location2'")).or(
|
||||
containsString("attribute 'location2' and its alias 'location1'")));
|
||||
exception.expectMessage(either(containsString("are present with values of [1] and [2]")).or(
|
||||
containsString("are present with values of [2] and [1]")));
|
||||
|
||||
synthesizedConfig.location1();
|
||||
exception.expectMessage(either(containsString("with values of [1] and [2]")).or(
|
||||
containsString("with values of [2] and [1]")));
|
||||
synthesizeAnnotation(config, clazz).location1();
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -1241,8 +1247,8 @@ public class AnnotationUtilsTests {
|
||||
|
||||
@Test
|
||||
public void synthesizeAnnotationWithAttributeAliasesWithDifferentValues() throws Exception {
|
||||
ContextConfig contextConfig = InternalAnnotationUtils.synthesizeAnnotation(ContextConfigMismatch.class.getAnnotation(ContextConfig.class));
|
||||
exception.expect(AnnotationConfigurationException.class);
|
||||
ContextConfig contextConfig = InternalAnnotationUtils.synthesizeAnnotation(ContextConfigMismatch.class.getAnnotation(ContextConfig.class));
|
||||
getValue(contextConfig);
|
||||
}
|
||||
|
||||
@@ -1306,23 +1312,29 @@ public class AnnotationUtilsTests {
|
||||
|
||||
private void assertMissingTextAttribute(Map<String, Object> attributes) {
|
||||
exception.expect(IllegalArgumentException.class);
|
||||
exception.expectMessage(startsWith("Attributes map"));
|
||||
exception.expectMessage(containsString("returned null for required attribute 'text'"));
|
||||
exception.expectMessage(containsString("defined by annotation type [" + AnnotationWithoutDefaults.class.getName() + "]"));
|
||||
exception.expectMessage(either(allOf(startsWith("Attributes map"),
|
||||
containsString("returned null for required attribute 'text'"),
|
||||
containsString("defined by annotation type ["
|
||||
+ AnnotationWithoutDefaults.class.getName() + "]"))).or(
|
||||
containsString(
|
||||
"No value found for attribute named 'text' in merged annotation")));
|
||||
synthesizeAnnotation(attributes, AnnotationWithoutDefaults.class, null);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void synthesizeAnnotationFromMapWithAttributeOfIncorrectType() throws Exception {
|
||||
Map<String, Object> map = Collections.singletonMap(VALUE, 42L);
|
||||
|
||||
exception.expect(IllegalArgumentException.class);
|
||||
exception.expectMessage(startsWith("Attributes map"));
|
||||
exception.expectMessage(containsString("returned a value of type [java.lang.Long]"));
|
||||
exception.expectMessage(containsString("for attribute 'value'"));
|
||||
exception.expectMessage(containsString("but a value of type [java.lang.String] is required"));
|
||||
exception.expectMessage(containsString("as defined by annotation type [" + Component.class.getName() + "]"));
|
||||
|
||||
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")));
|
||||
synthesizeAnnotation(map, Component.class, null);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user