diff --git a/spring-core/src/main/java/org/springframework/core/annotation/AnnotationAttributes.java b/spring-core/src/main/java/org/springframework/core/annotation/AnnotationAttributes.java index 1ab67ab6afd..fd4b5426657 100644 --- a/spring-core/src/main/java/org/springframework/core/annotation/AnnotationAttributes.java +++ b/spring-core/src/main/java/org/springframework/core/annotation/AnnotationAttributes.java @@ -98,6 +98,7 @@ public class AnnotationAttributes extends LinkedHashMap { this.displayName = "unknown"; } + /** * Get the type of annotation represented by this * {@code AnnotationAttributes} instance. @@ -128,7 +129,6 @@ public class AnnotationAttributes extends LinkedHashMap { *

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 { */ public String getAliasedString(String attributeName, Class annotationType, Object annotationSource) { + return getRequiredAttributeWithAlias(attributeName, annotationType, annotationSource, String.class); } @@ -172,7 +173,6 @@ public class AnnotationAttributes extends LinkedHashMap { *

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 { */ public String[] getAliasedStringArray(String attributeName, Class annotationType, Object annotationSource) { + return getRequiredAttributeWithAlias(attributeName, annotationType, annotationSource, String[].class); } @@ -270,7 +271,6 @@ public class AnnotationAttributes extends LinkedHashMap { *

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 { */ public Class[] getAliasedClassArray(String attributeName, Class annotationType, Object annotationSource) { + return getRequiredAttributeWithAlias(attributeName, annotationType, annotationSource, Class[].class); } @@ -378,8 +379,9 @@ public class AnnotationAttributes extends LinkedHashMap { 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 { *

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 { 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 { private T getAttribute(String attributeName, Class 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 { 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 { return String.valueOf(value); } + /** * Return an {@link AnnotationAttributes} instance based on the given map. *

If the map is already an {@code AnnotationAttributes} instance, it diff --git a/spring-core/src/main/java/org/springframework/core/type/classreading/AnnotationReadingVisitorUtils.java b/spring-core/src/main/java/org/springframework/core/type/classreading/AnnotationReadingVisitorUtils.java index aef400633af..d63c72ffa3c 100644 --- a/spring-core/src/main/java/org/springframework/core/type/classreading/AnnotationReadingVisitorUtils.java +++ b/spring-core/src/main/java/org/springframework/core/type/classreading/AnnotationReadingVisitorUtils.java @@ -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 { 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; diff --git a/spring-core/src/test/java/org/springframework/core/annotation/AnnotationAttributesTests.java b/spring-core/src/test/java/org/springframework/core/annotation/AnnotationAttributesTests.java index 15eaec6b309..7a963439cd8 100644 --- a/spring-core/src/test/java/org/springframework/core/annotation/AnnotationAttributesTests.java +++ b/spring-core/src/test/java/org/springframework/core/annotation/AnnotationAttributesTests.java @@ -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 { assertThat(attributes.getNumber("number"), equalTo(42)); assertThat(attributes.getAnnotation("anno").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