diff --git a/spring-context/src/main/java/org/springframework/context/annotation/ConfigurationClassParser.java b/spring-context/src/main/java/org/springframework/context/annotation/ConfigurationClassParser.java index 046889c47e..2e3800e14f 100644 --- a/spring-context/src/main/java/org/springframework/context/annotation/ConfigurationClassParser.java +++ b/spring-context/src/main/java/org/springframework/context/annotation/ConfigurationClassParser.java @@ -18,6 +18,7 @@ package org.springframework.context.annotation; import java.io.FileNotFoundException; import java.io.IOException; +import java.lang.annotation.Annotation; import java.net.UnknownHostException; import java.util.ArrayDeque; import java.util.ArrayList; @@ -55,6 +56,7 @@ import org.springframework.core.OrderComparator; import org.springframework.core.Ordered; import org.springframework.core.annotation.AnnotationAttributes; import org.springframework.core.annotation.AnnotationAwareOrderComparator; +import org.springframework.core.annotation.AnnotationUtils; import org.springframework.core.env.CompositePropertySource; import org.springframework.core.env.ConfigurableEnvironment; import org.springframework.core.env.Environment; @@ -659,8 +661,11 @@ class ConfigurationClassParser { return new SourceClass(Object.class); } try { - // Sanity test that we can read annotations, if not fall back to ASM - classType.getAnnotations(); + // Sanity test that we can reflectively read annotations, + // including Class attributes; if not -> fall back to ASM + for (Annotation ann : classType.getAnnotations()) { + AnnotationUtils.validateAnnotation(ann); + } return new SourceClass(classType); } catch (Throwable ex) { diff --git a/spring-core/src/main/java/org/springframework/core/annotation/AnnotatedElementUtils.java b/spring-core/src/main/java/org/springframework/core/annotation/AnnotatedElementUtils.java index 63a769b4f8..0bd78ec559 100644 --- a/spring-core/src/main/java/org/springframework/core/annotation/AnnotatedElementUtils.java +++ b/spring-core/src/main/java/org/springframework/core/annotation/AnnotatedElementUtils.java @@ -60,10 +60,9 @@ import org.springframework.util.MultiValueMap; * individual method for details on which search algorithm is used. * *
Get semantics are limited to searching for annotations - * that are either present on an {@code AnnotatedElement} (i.e., - * declared locally or {@linkplain java.lang.annotation.Inherited inherited}) - * or declared within the annotation hierarchy above the - * {@code AnnotatedElement}. + * that are either present on an {@code AnnotatedElement} (i.e. declared + * locally or {@linkplain java.lang.annotation.Inherited inherited}) or declared + * within the annotation hierarchy above the {@code AnnotatedElement}. * *
Find semantics are much more exhaustive, providing * get semantics plus support for the following: @@ -77,14 +76,13 @@ import org.springframework.util.MultiValueMap; * * *
Methods following get semantics will honor the contract of - * Java's {@link java.lang.annotation.Inherited @Inherited} annotation except - * that locally declared annotations (including custom composed annotations) - * will be favored over inherited annotations. In contrast, methods following - * find semantics will completely ignore the presence of - * {@code @Inherited} since the find search algorithm manually - * traverses type and method hierarchies and thereby implicitly supports - * annotation inheritance without the need for {@code @Inherited}. + *
Methods following get semantics will honor the contract of Java's
+ * {@link java.lang.annotation.Inherited @Inherited} annotation except that locally
+ * declared annotations (including custom composed annotations) will be favored over
+ * inherited annotations. In contrast, methods following find semantics
+ * will completely ignore the presence of {@code @Inherited} since the find
+ * search algorithm manually traverses type and method hierarchies and thereby
+ * implicitly supports annotation inheritance without a need for {@code @Inherited}.
*
* @author Phillip Webb
* @author Juergen Hoeller
@@ -794,7 +792,7 @@ public class AnnotatedElementUtils {
* @param annotationName the fully qualified class name of the annotation
* type to find (as an alternative to {@code annotationType})
* @param processor the processor to delegate to
- * @return the result of the processor, potentially {@code null}
+ * @return the result of the processor (potentially {@code null})
*/
@Nullable
private static This method not failing indicates that {@link #getAnnotationAttributes(Annotation)}
+ * won't failure either (when attempted later on).
+ * @param annotation the annotation to validate
+ * @throws IllegalStateException if a declared {@code Class} attribute could not be read
+ * @since 4.3.15
+ * @see Class#getAnnotations()
+ * @see #getAnnotationAttributes(Annotation)
+ */
+ public static void validateAnnotation(Annotation annotation) {
+ for (Method method : getAttributeMethods(annotation.annotationType())) {
+ if (method.getReturnType() == Class.class) {
+ try {
+ method.invoke(annotation);
+ }
+ catch (Throwable ex) {
+ throw new IllegalStateException("Could not obtain annotation attribute value for " + method, ex);
+ }
+ }
+ }
+ }
+
/**
* Retrieve the given annotation's attributes as a {@link Map}, preserving all
* attribute types.
@@ -1835,13 +1860,13 @@ public abstract class AnnotationUtils {
if (element instanceof Class && Annotation.class.isAssignableFrom((Class>) element)) {
// Meta-annotation or (default) value lookup on an annotation type
if (loggerToUse.isDebugEnabled()) {
- loggerToUse.debug("Failed to meta-introspect annotation [" + element + "]: " + ex);
+ loggerToUse.debug("Failed to meta-introspect annotation " + element + ": " + ex);
}
}
else {
// Direct annotation lookup on regular Class, Method, Field
if (loggerToUse.isInfoEnabled()) {
- loggerToUse.info("Failed to introspect annotations on [" + element + "]: " + ex);
+ loggerToUse.info("Failed to introspect annotations on " + element + ": " + ex);
}
}
}