Validate declared annotations before deciding between reflection and ASM

Issue: SPR-16564
This commit is contained in:
Juergen Hoeller
2018-03-28 01:20:59 +02:00
parent c1cb0311aa
commit 7cafa6764c
3 changed files with 55 additions and 26 deletions

View File

@@ -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,

View File

@@ -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);
}
}
}