Validate declared annotations before deciding between reflection and ASM
Issue: SPR-16564
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2017 the original author or authors.
|
||||
* Copyright 2002-2018 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.
|
||||
@@ -59,10 +59,9 @@ import org.springframework.util.MultiValueMap;
|
||||
* individual method for details on which search algorithm is used.
|
||||
*
|
||||
* <p><strong>Get semantics</strong> are limited to searching for annotations
|
||||
* that are either <em>present</em> on an {@code AnnotatedElement} (i.e.,
|
||||
* declared locally or {@linkplain java.lang.annotation.Inherited inherited})
|
||||
* or declared within the annotation hierarchy <em>above</em> the
|
||||
* {@code AnnotatedElement}.
|
||||
* that are either <em>present</em> on an {@code AnnotatedElement} (i.e. declared
|
||||
* locally or {@linkplain java.lang.annotation.Inherited inherited}) or declared
|
||||
* within the annotation hierarchy <em>above</em> the {@code AnnotatedElement}.
|
||||
*
|
||||
* <p><strong>Find semantics</strong> are much more exhaustive, providing
|
||||
* <em>get semantics</em> plus support for the following:
|
||||
@@ -76,14 +75,13 @@ import org.springframework.util.MultiValueMap;
|
||||
* </ul>
|
||||
*
|
||||
* <h3>Support for {@code @Inherited}</h3>
|
||||
* <p>Methods following <em>get semantics</em> 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
|
||||
* <em>find semantics</em> will completely ignore the presence of
|
||||
* {@code @Inherited} since the <em>find</em> search algorithm manually
|
||||
* traverses type and method hierarchies and thereby implicitly supports
|
||||
* annotation inheritance without the need for {@code @Inherited}.
|
||||
* <p>Methods following <em>get semantics</em> 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 <em>find semantics</em>
|
||||
* will completely ignore the presence of {@code @Inherited} since the <em>find</em>
|
||||
* 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
|
||||
@@ -873,7 +871,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})
|
||||
*/
|
||||
private static <T> T searchWithGetSemantics(AnnotatedElement element, Class<? extends Annotation> annotationType,
|
||||
String annotationName, Processor<T> processor) {
|
||||
@@ -892,7 +890,7 @@ public class AnnotatedElementUtils {
|
||||
* @param containerType the type of the container that holds repeatable
|
||||
* annotations, or {@code null} if the annotation is not repeatable
|
||||
* @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})
|
||||
* @since 4.3
|
||||
*/
|
||||
private static <T> T searchWithGetSemantics(AnnotatedElement element, Class<? extends Annotation> annotationType,
|
||||
@@ -923,7 +921,7 @@ public class AnnotatedElementUtils {
|
||||
* @param processor the processor to delegate to
|
||||
* @param visited the set of annotated elements that have already been visited
|
||||
* @param metaDepth the meta-depth of the annotation
|
||||
* @return the result of the processor, potentially {@code null}
|
||||
* @return the result of the processor (potentially {@code null})
|
||||
*/
|
||||
private static <T> T searchWithGetSemantics(AnnotatedElement element, Class<? extends Annotation> annotationType,
|
||||
String annotationName, Class<? extends Annotation> containerType, Processor<T> processor,
|
||||
@@ -984,7 +982,7 @@ public class AnnotatedElementUtils {
|
||||
* @param processor the processor to delegate to
|
||||
* @param visited the set of annotated elements that have already been visited
|
||||
* @param metaDepth the meta-depth of the annotation
|
||||
* @return the result of the processor, potentially {@code null}
|
||||
* @return the result of the processor (potentially {@code null})
|
||||
* @since 4.2
|
||||
*/
|
||||
private static <T> T searchWithGetSemanticsInAnnotations(AnnotatedElement element,
|
||||
@@ -1053,7 +1051,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})
|
||||
* @since 4.2
|
||||
*/
|
||||
private static <T> T searchWithFindSemantics(AnnotatedElement element, Class<? extends Annotation> annotationType,
|
||||
@@ -1073,7 +1071,7 @@ public class AnnotatedElementUtils {
|
||||
* @param containerType the type of the container that holds repeatable
|
||||
* annotations, or {@code null} if the annotation is not repeatable
|
||||
* @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})
|
||||
* @since 4.3
|
||||
*/
|
||||
private static <T> T searchWithFindSemantics(AnnotatedElement element, Class<? extends Annotation> annotationType,
|
||||
@@ -1109,7 +1107,7 @@ public class AnnotatedElementUtils {
|
||||
* @param processor the processor to delegate to
|
||||
* @param visited the set of annotated elements that have already been visited
|
||||
* @param metaDepth the meta-depth of the annotation
|
||||
* @return the result of the processor, potentially {@code null}
|
||||
* @return the result of the processor (potentially {@code null})
|
||||
* @since 4.2
|
||||
*/
|
||||
private static <T> T searchWithFindSemantics(AnnotatedElement element, Class<? extends Annotation> annotationType,
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2002-2017 the original author or authors.
|
||||
* Copyright 2002-2018 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.
|
||||
@@ -932,6 +932,32 @@ public abstract class AnnotationUtils {
|
||||
return (annotationType != null && annotationType.startsWith("java.lang.annotation"));
|
||||
}
|
||||
|
||||
/**
|
||||
* Check the declared attributes of the given annotation, in particular covering
|
||||
* Google App Engine's late arrival of {@code TypeNotPresentExceptionProxy} for
|
||||
* {@code Class} values (instead of early {@code Class.getAnnotations() failure}.
|
||||
* <p>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())) {
|
||||
Class<?> returnType = method.getReturnType();
|
||||
if (returnType == Class.class || returnType == 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.
|
||||
@@ -1882,13 +1908,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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user