Browse Source

AnnotationAttributes stores and re-throws resolution exceptions

Issue: SPR-13177
pull/831/merge
Juergen Hoeller 11 years ago
parent
commit
b7acddbb19
  1. 43
      spring-core/src/main/java/org/springframework/core/annotation/AnnotationAttributes.java
  2. 12
      spring-core/src/main/java/org/springframework/core/type/classreading/AnnotationReadingVisitorUtils.java
  3. 10
      spring-core/src/test/java/org/springframework/core/annotation/AnnotationAttributesTests.java

43
spring-core/src/main/java/org/springframework/core/annotation/AnnotationAttributes.java

@ -98,6 +98,7 @@ public class AnnotationAttributes extends LinkedHashMap<String, Object> { @@ -98,6 +98,7 @@ public class AnnotationAttributes extends LinkedHashMap<String, Object> {
this.displayName = "unknown";
}
/**
* Get the type of annotation represented by this
* {@code AnnotationAttributes} instance.
@ -128,7 +129,6 @@ public class AnnotationAttributes extends LinkedHashMap<String, Object> { @@ -128,7 +129,6 @@ public class AnnotationAttributes extends LinkedHashMap<String, Object> {
* <p>If there is no value stored under the specified {@code attributeName}
* but the attribute has an alias declared via {@code @AliasFor}, the
* value of the alias will be returned.
*
* @param attributeName the name of the attribute to get; never
* {@code null} or empty
* @param annotationType the type of annotation represented by this
@ -146,6 +146,7 @@ public class AnnotationAttributes extends LinkedHashMap<String, Object> { @@ -146,6 +146,7 @@ public class AnnotationAttributes extends LinkedHashMap<String, Object> {
*/
public String getAliasedString(String attributeName, Class<? extends Annotation> annotationType,
Object annotationSource) {
return getRequiredAttributeWithAlias(attributeName, annotationType, annotationSource, String.class);
}
@ -172,7 +173,6 @@ public class AnnotationAttributes extends LinkedHashMap<String, Object> { @@ -172,7 +173,6 @@ public class AnnotationAttributes extends LinkedHashMap<String, Object> {
* <p>If there is no value stored under the specified {@code attributeName}
* but the attribute has an alias declared via {@code @AliasFor}, the
* value of the alias will be returned.
*
* @param attributeName the name of the attribute to get; never
* {@code null} or empty
* @param annotationType the type of annotation represented by this
@ -189,6 +189,7 @@ public class AnnotationAttributes extends LinkedHashMap<String, Object> { @@ -189,6 +189,7 @@ public class AnnotationAttributes extends LinkedHashMap<String, Object> {
*/
public String[] getAliasedStringArray(String attributeName, Class<? extends Annotation> annotationType,
Object annotationSource) {
return getRequiredAttributeWithAlias(attributeName, annotationType, annotationSource, String[].class);
}
@ -270,7 +271,6 @@ public class AnnotationAttributes extends LinkedHashMap<String, Object> { @@ -270,7 +271,6 @@ public class AnnotationAttributes extends LinkedHashMap<String, Object> {
* <p>If there is no value stored under the specified {@code attributeName}
* but the attribute has an alias declared via {@code @AliasFor}, the
* value of the alias will be returned.
*
* @param attributeName the name of the attribute to get; never
* {@code null} or empty
* @param annotationType the type of annotation represented by this
@ -287,6 +287,7 @@ public class AnnotationAttributes extends LinkedHashMap<String, Object> { @@ -287,6 +287,7 @@ public class AnnotationAttributes extends LinkedHashMap<String, Object> {
*/
public Class<?>[] getAliasedClassArray(String attributeName, Class<? extends Annotation> annotationType,
Object annotationSource) {
return getRequiredAttributeWithAlias(attributeName, annotationType, annotationSource, Class[].class);
}
@ -378,8 +379,9 @@ public class AnnotationAttributes extends LinkedHashMap<String, Object> { @@ -378,8 +379,9 @@ public class AnnotationAttributes extends LinkedHashMap<String, Object> {
Assert.hasText(attributeName, "attributeName must not be null or empty");
Object value = get(attributeName);
assertAttributePresence(attributeName, value);
if (!expectedType.isInstance(value) && expectedType.isArray()
&& expectedType.getComponentType().isInstance(value)) {
assertNotException(attributeName, value);
if (!expectedType.isInstance(value) && expectedType.isArray() &&
expectedType.getComponentType().isInstance(value)) {
Object array = Array.newInstance(expectedType.getComponentType(), 1);
Array.set(array, 0, value);
value = array;
@ -395,7 +397,6 @@ public class AnnotationAttributes extends LinkedHashMap<String, Object> { @@ -395,7 +397,6 @@ public class AnnotationAttributes extends LinkedHashMap<String, Object> {
* <p>If there is no value stored under the specified {@code attributeName}
* but the attribute has an alias declared via {@code @AliasFor}, the
* value of the alias will be returned.
*
* @param attributeName the name of the attribute to get; never
* {@code null} or empty
* @param annotationType the type of annotation represented by this
@ -427,10 +428,10 @@ public class AnnotationAttributes extends LinkedHashMap<String, Object> { @@ -427,10 +428,10 @@ public class AnnotationAttributes extends LinkedHashMap<String, Object> {
if (!ObjectUtils.nullSafeEquals(attributeValue, aliasValue) && attributeDeclared && aliasDeclared) {
String elementName = (annotationSource == null ? "unknown element" : annotationSource.toString());
String msg = String.format("In annotation [%s] declared on [%s], "
+ "attribute [%s] and its alias [%s] are present with values of [%s] and [%s], "
+ "but only one is permitted.", annotationType.getName(), elementName, attributeName, aliasName,
ObjectUtils.nullSafeToString(attributeValue), ObjectUtils.nullSafeToString(aliasValue));
String msg = String.format("In annotation [%s] declared on [%s], attribute [%s] and its alias [%s] " +
"are present with values of [%s] and [%s], but only one is permitted.",
annotationType.getName(), elementName, attributeName, aliasName,
ObjectUtils.nullSafeToString(attributeValue), ObjectUtils.nullSafeToString(aliasValue));
throw new AnnotationConfigurationException(msg);
}
@ -458,6 +459,7 @@ public class AnnotationAttributes extends LinkedHashMap<String, Object> { @@ -458,6 +459,7 @@ public class AnnotationAttributes extends LinkedHashMap<String, Object> {
private <T> T getAttribute(String attributeName, Class<T> expectedType) {
Object value = get(attributeName);
if (value != null) {
assertNotException(attributeName, value);
assertAttributeType(attributeName, value, expectedType);
}
return (T) value;
@ -466,24 +468,32 @@ public class AnnotationAttributes extends LinkedHashMap<String, Object> { @@ -466,24 +468,32 @@ public class AnnotationAttributes extends LinkedHashMap<String, Object> {
private void assertAttributePresence(String attributeName, Object attributeValue) {
if (attributeValue == null) {
throw new IllegalArgumentException(String.format(
"Attribute '%s' not found in attributes for annotation [%s]", attributeName, this.displayName));
"Attribute '%s' not found in attributes for annotation [%s]", attributeName, this.displayName));
}
}
private void assertAttributePresence(String attributeName, String aliasName, Object attributeValue) {
if (attributeValue == null) {
throw new IllegalArgumentException(String.format(
"Neither attribute '%s' nor its alias '%s' was found in attributes for annotation [%s]", attributeName,
aliasName, this.displayName));
"Neither attribute '%s' nor its alias '%s' was found in attributes for annotation [%s]",
attributeName, aliasName, this.displayName));
}
}
private void assertNotException(String attributeName, Object attributeValue) {
if (attributeValue instanceof Exception) {
throw new IllegalArgumentException(String.format(
"Attribute '%s' for annotation [%s] was not resolvable due to exception [%s]",
attributeName, this.displayName, attributeValue), (Exception) attributeValue);
}
}
private void assertAttributeType(String attributeName, Object attributeValue, Class<?> expectedType) {
if (!expectedType.isInstance(attributeValue)) {
throw new IllegalArgumentException(String.format(
"Attribute '%s' is of type [%s], but [%s] was expected in attributes for annotation [%s]",
attributeName, attributeValue.getClass().getSimpleName(), expectedType.getSimpleName(),
this.displayName));
"Attribute '%s' is of type [%s], but [%s] was expected in attributes for annotation [%s]",
attributeName, attributeValue.getClass().getSimpleName(), expectedType.getSimpleName(),
this.displayName));
}
}
@ -532,6 +542,7 @@ public class AnnotationAttributes extends LinkedHashMap<String, Object> { @@ -532,6 +542,7 @@ public class AnnotationAttributes extends LinkedHashMap<String, Object> {
return String.valueOf(value);
}
/**
* Return an {@link AnnotationAttributes} instance based on the given map.
* <p>If the map is already an {@code AnnotationAttributes} instance, it

12
spring-core/src/main/java/org/springframework/core/type/classreading/AnnotationReadingVisitorUtils.java

@ -62,15 +62,15 @@ abstract class AnnotationReadingVisitorUtils { @@ -62,15 +62,15 @@ abstract class AnnotationReadingVisitorUtils {
}
}
else if (value instanceof Type) {
value = (classValuesAsString ? ((Type) value).getClassName()
: classLoader.loadClass(((Type) value).getClassName()));
value = (classValuesAsString ? ((Type) value).getClassName() :
classLoader.loadClass(((Type) value).getClassName()));
}
else if (value instanceof Type[]) {
Type[] array = (Type[]) value;
Object[] convArray = (classValuesAsString ? new String[array.length] : new Class<?>[array.length]);
for (int i = 0; i < array.length; i++) {
convArray[i] = (classValuesAsString ? array[i].getClassName()
: classLoader.loadClass(array[i].getClassName()));
convArray[i] = (classValuesAsString ? array[i].getClassName() :
classLoader.loadClass(array[i].getClassName()));
}
value = convArray;
}
@ -90,8 +90,8 @@ abstract class AnnotationReadingVisitorUtils { @@ -90,8 +90,8 @@ abstract class AnnotationReadingVisitorUtils {
result.put(entry.getKey(), value);
}
catch (Exception ex) {
// Class not found - can't resolve class reference in annotation
// attribute.
// Class not found - can't resolve class reference in annotation attribute.
result.put(entry.getKey(), ex);
}
}
return result;

10
spring-core/src/test/java/org/springframework/core/annotation/AnnotationAttributesTests.java

@ -57,6 +57,7 @@ public class AnnotationAttributesTests { @@ -57,6 +57,7 @@ public class AnnotationAttributesTests {
attributes.put("number", 42);
attributes.put("anno", nestedAttributes);
attributes.put("annoArray", new AnnotationAttributes[] { nestedAttributes });
attributes.put("unresolvableClass", new ClassNotFoundException("myclass"));
assertThat(attributes.getString("name"), equalTo("dave"));
assertThat(attributes.getStringArray("names"), equalTo(new String[] { "dave", "frank", "hal" }));
@ -68,6 +69,15 @@ public class AnnotationAttributesTests { @@ -68,6 +69,15 @@ public class AnnotationAttributesTests {
assertThat(attributes.<Integer>getNumber("number"), equalTo(42));
assertThat(attributes.getAnnotation("anno").<Integer>getNumber("value"), equalTo(10));
assertThat(attributes.getAnnotationArray("annoArray")[0].getString("name"), equalTo("algernon"));
try {
attributes.getClass("unresolvableClass");
fail("Should have thrown IllegalArgumentException");
}
catch (IllegalArgumentException ex) {
assertTrue(ex.getCause() instanceof ClassNotFoundException);
assertTrue(ex.getMessage().contains("myclass"));
}
}
@Test

Loading…
Cancel
Save