Validate declared annotations before deciding between reflection and ASM

Issue: SPR-16564
This commit is contained in:
Juergen Hoeller
2018-03-12 13:40:26 +01:00
parent 1b1a69a144
commit 50e980c02f
3 changed files with 51 additions and 23 deletions

View File

@@ -60,10 +60,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:
@@ -77,14 +76,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
@@ -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 <T> T searchWithGetSemantics(AnnotatedElement element,
@@ -815,7 +813,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
*/
@Nullable
@@ -848,7 +846,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})
*/
@Nullable
private static <T> T searchWithGetSemantics(AnnotatedElement element,
@@ -909,7 +907,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
*/
@Nullable
@@ -979,7 +977,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
*/
@Nullable
@@ -1001,7 +999,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
*/
@Nullable
@@ -1039,7 +1037,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
*/
@Nullable

View File

@@ -898,6 +898,31 @@ 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())) {
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);
}
}
}