Browse Source

Minimize reflective interaction with annotation instances during retrieval

Issue: SPR-15387
pull/1377/head
Juergen Hoeller 8 years ago
parent
commit
3037277d0e
  1. 89
      spring-core/src/main/java/org/springframework/core/annotation/AnnotatedElementUtils.java
  2. 47
      spring-core/src/main/java/org/springframework/core/annotation/AnnotationUtils.java
  3. 9
      spring-core/src/main/java/org/springframework/core/type/classreading/AnnotationAttributesReadingVisitor.java
  4. 22
      spring-test/src/main/java/org/springframework/test/util/MetaAnnotationUtils.java

89
spring-core/src/main/java/org/springframework/core/annotation/AnnotatedElementUtils.java

@ -427,10 +427,10 @@ public class AnnotatedElementUtils { @@ -427,10 +427,10 @@ public class AnnotatedElementUtils {
* single annotation and within annotation hierarchies.
* <p>This method follows <em>get semantics</em> as described in the
* {@linkplain AnnotatedElementUtils class-level javadoc}.
* @param element the annotated element; never {@code null}
* @param annotationType the annotation type to find; never {@code null}
* @return the set of all merged, synthesized {@code Annotations} found, or an empty
* set if none were found
* @param element the annotated element (never {@code null})
* @param annotationType the annotation type to find (never {@code null})
* @return the set of all merged, synthesized {@code Annotations} found,
* or an empty set if none were found
* @since 4.3
* @see #getMergedAnnotation(AnnotatedElement, Class)
* @see #getAllAnnotationAttributes(AnnotatedElement, String)
@ -460,10 +460,10 @@ public class AnnotatedElementUtils { @@ -460,10 +460,10 @@ public class AnnotatedElementUtils {
* single annotation and within annotation hierarchies.
* <p>This method follows <em>get semantics</em> as described in the
* {@linkplain AnnotatedElementUtils class-level javadoc}.
* @param element the annotated element; never {@code null}
* @param annotationType the annotation type to find; never {@code null}
* @return the set of all merged repeatable {@code Annotations} found, or an empty
* set if none were found
* @param element the annotated element (never {@code null})
* @param annotationType the annotation type to find (never {@code null})
* @return the set of all merged repeatable {@code Annotations} found,
* or an empty set if none were found
* @since 4.3
* @see #getMergedAnnotation(AnnotatedElement, Class)
* @see #getAllMergedAnnotations(AnnotatedElement, Class)
@ -488,13 +488,13 @@ public class AnnotatedElementUtils { @@ -488,13 +488,13 @@ public class AnnotatedElementUtils {
* single annotation and within annotation hierarchies.
* <p>This method follows <em>get semantics</em> as described in the
* {@linkplain AnnotatedElementUtils class-level javadoc}.
* @param element the annotated element; never {@code null}
* @param annotationType the annotation type to find; never {@code null}
* @param element the annotated element (never {@code null})
* @param annotationType the annotation type to find (never {@code null})
* @param containerType the type of the container that holds the annotations;
* may be {@code null} if the container type should be looked up via
* {@link java.lang.annotation.Repeatable}
* @return the set of all merged repeatable {@code Annotations} found, or an empty
* set if none were found
* @return the set of all merged repeatable {@code Annotations} found,
* or an empty set if none were found
* @since 4.3
* @see #getMergedAnnotation(AnnotatedElement, Class)
* @see #getAllMergedAnnotations(AnnotatedElement, Class)
@ -724,10 +724,10 @@ public class AnnotatedElementUtils { @@ -724,10 +724,10 @@ public class AnnotatedElementUtils {
* single annotation and within annotation hierarchies.
* <p>This method follows <em>find semantics</em> as described in the
* {@linkplain AnnotatedElementUtils class-level javadoc}.
* @param element the annotated element; never {@code null}
* @param annotationType the annotation type to find; never {@code null}
* @return the set of all merged, synthesized {@code Annotations} found, or an empty
* set if none were found
* @param element the annotated element (never {@code null})
* @param annotationType the annotation type to find (never {@code null})
* @return the set of all merged, synthesized {@code Annotations} found,
* or an empty set if none were found
* @since 4.3
* @see #findMergedAnnotation(AnnotatedElement, Class)
* @see #getAllMergedAnnotations(AnnotatedElement, Class)
@ -756,10 +756,10 @@ public class AnnotatedElementUtils { @@ -756,10 +756,10 @@ public class AnnotatedElementUtils {
* single annotation and within annotation hierarchies.
* <p>This method follows <em>find semantics</em> as described in the
* {@linkplain AnnotatedElementUtils class-level javadoc}.
* @param element the annotated element; never {@code null}
* @param annotationType the annotation type to find; never {@code null}
* @return the set of all merged repeatable {@code Annotations} found, or an empty
* set if none were found
* @param element the annotated element (never {@code null})
* @param annotationType the annotation type to find (never {@code null})
* @return the set of all merged repeatable {@code Annotations} found,
* or an empty set if none were found
* @since 4.3
* @see #findMergedAnnotation(AnnotatedElement, Class)
* @see #findAllMergedAnnotations(AnnotatedElement, Class)
@ -784,13 +784,13 @@ public class AnnotatedElementUtils { @@ -784,13 +784,13 @@ public class AnnotatedElementUtils {
* single annotation and within annotation hierarchies.
* <p>This method follows <em>find semantics</em> as described in the
* {@linkplain AnnotatedElementUtils class-level javadoc}.
* @param element the annotated element; never {@code null}
* @param annotationType the annotation type to find; never {@code null}
* @param element the annotated element (never {@code null})
* @param annotationType the annotation type to find (never {@code null})
* @param containerType the type of the container that holds the annotations;
* may be {@code null} if the container type should be looked up via
* {@link java.lang.annotation.Repeatable}
* @return the set of all merged repeatable {@code Annotations} found, or an empty
* set if none were found
* @return the set of all merged repeatable {@code Annotations} found,
* or an empty set if none were found
* @since 4.3
* @see #findMergedAnnotation(AnnotatedElement, Class)
* @see #findAllMergedAnnotations(AnnotatedElement, Class)
@ -947,9 +947,10 @@ public class AnnotatedElementUtils { @@ -947,9 +947,10 @@ public class AnnotatedElementUtils {
// Search in annotations
for (Annotation annotation : annotations) {
if (!AnnotationUtils.isInJavaLangAnnotationPackage(annotation)) {
if (annotation.annotationType() == annotationType ||
annotation.annotationType().getName().equals(annotationName) ||
Class<? extends Annotation> currentAnnotationType = annotation.annotationType();
if (!AnnotationUtils.isInJavaLangAnnotationPackage(currentAnnotationType)) {
if (currentAnnotationType == annotationType ||
currentAnnotationType.getName().equals(annotationName) ||
processor.alwaysProcesses()) {
T result = processor.process(element, annotation, metaDepth);
if (result != null) {
@ -962,7 +963,7 @@ public class AnnotatedElementUtils { @@ -962,7 +963,7 @@ public class AnnotatedElementUtils {
}
}
// Repeatable annotations in container?
else if (annotation.annotationType() == containerType) {
else if (currentAnnotationType == containerType) {
for (Annotation contained : getRawAnnotationsFromContainer(element, annotation)) {
T result = processor.process(element, contained, metaDepth);
if (result != null) {
@ -977,8 +978,9 @@ public class AnnotatedElementUtils { @@ -977,8 +978,9 @@ public class AnnotatedElementUtils {
// Recursively search in meta-annotations
for (Annotation annotation : annotations) {
if (!AnnotationUtils.isInJavaLangAnnotationPackage(annotation)) {
T result = searchWithGetSemantics(annotation.annotationType(), annotationType,
Class<? extends Annotation> currentAnnotationType = annotation.annotationType();
if (!AnnotationUtils.isInJavaLangAnnotationPackage(currentAnnotationType)) {
T result = searchWithGetSemantics(currentAnnotationType, annotationType,
annotationName, containerType, processor, visited, metaDepth + 1);
if (result != null) {
processor.postProcess(element, annotation, result);
@ -1051,7 +1053,7 @@ public class AnnotatedElementUtils { @@ -1051,7 +1053,7 @@ public class AnnotatedElementUtils {
* have already been <em>visited</em>.
* <p>The {@code metaDepth} parameter is explained in the
* {@link Processor#process process()} method of the {@link Processor} API.
* @param element the annotated element; never {@code null}
* @param element the annotated element (never {@code null})
* @param annotationType the annotation type to find
* @param annotationName the fully qualified class name of the annotation
* type to find (as an alternative to {@code annotationType})
@ -1077,11 +1079,11 @@ public class AnnotatedElementUtils { @@ -1077,11 +1079,11 @@ public class AnnotatedElementUtils {
// Search in local annotations
for (Annotation annotation : annotations) {
if (!AnnotationUtils.isInJavaLangAnnotationPackage(annotation)) {
if (annotation.annotationType() == annotationType
|| annotation.annotationType().getName().equals(annotationName)
|| processor.alwaysProcesses()) {
Class<? extends Annotation> currentAnnotationType = annotation.annotationType();
if (!AnnotationUtils.isInJavaLangAnnotationPackage(currentAnnotationType)) {
if (currentAnnotationType == annotationType ||
currentAnnotationType.getName().equals(annotationName) ||
processor.alwaysProcesses()) {
T result = processor.process(element, annotation, metaDepth);
if (result != null) {
if (processor.aggregates() && metaDepth == 0) {
@ -1093,7 +1095,7 @@ public class AnnotatedElementUtils { @@ -1093,7 +1095,7 @@ public class AnnotatedElementUtils {
}
}
// Repeatable annotations in container?
else if (annotation.annotationType() == containerType) {
else if (currentAnnotationType == containerType) {
for (Annotation contained : getRawAnnotationsFromContainer(element, annotation)) {
T result = processor.process(element, contained, metaDepth);
if (result != null) {
@ -1108,11 +1110,12 @@ public class AnnotatedElementUtils { @@ -1108,11 +1110,12 @@ public class AnnotatedElementUtils {
// Search in meta annotations on local annotations
for (Annotation annotation : annotations) {
if (!AnnotationUtils.isInJavaLangAnnotationPackage(annotation)) {
T result = searchWithFindSemantics(annotation.annotationType(), annotationType, annotationName,
Class<? extends Annotation> currentAnnotationType = annotation.annotationType();
if (!AnnotationUtils.isInJavaLangAnnotationPackage(currentAnnotationType)) {
T result = searchWithFindSemantics(currentAnnotationType, annotationType, annotationName,
containerType, processor, visited, metaDepth + 1);
if (result != null) {
processor.postProcess(annotation.annotationType(), annotation, result);
processor.postProcess(currentAnnotationType, annotation, result);
if (processor.aggregates() && metaDepth == 0) {
aggregatedResults.add(result);
}
@ -1252,7 +1255,7 @@ public class AnnotatedElementUtils { @@ -1252,7 +1255,7 @@ public class AnnotatedElementUtils {
* Resolve the container type for the supplied repeatable {@code annotationType}.
* <p>Delegates to {@link AnnotationUtils#resolveContainerAnnotationType(Class)}.
* @param annotationType the annotation type to resolve the container for
* @return the container type; never {@code null}
* @return the container type (never {@code null})
* @throws IllegalArgumentException if the container type cannot be resolved
* @since 4.3
*/
@ -1403,8 +1406,8 @@ public class AnnotatedElementUtils { @@ -1403,8 +1406,8 @@ public class AnnotatedElementUtils {
* responsible for asking this processor if it {@link #aggregates} results
* and then adding the post-processed results to the list returned by this
* method.
* @return the list of results aggregated by this processor; never
* {@code null} unless {@link #aggregates} returns {@code false}
* @return the list of results aggregated by this processor
* (never {@code null} unless {@link #aggregates} returns {@code false})
* @see #aggregates
* @since 4.3
*/

47
spring-core/src/main/java/org/springframework/core/annotation/AnnotationUtils.java

@ -64,7 +64,7 @@ import org.springframework.util.StringUtils; @@ -64,7 +64,7 @@ import org.springframework.util.StringUtils;
* <h3>Terminology</h3>
* The terms <em>directly present</em>, <em>indirectly present</em>, and
* <em>present</em> have the same meanings as defined in the class-level
* Javadoc for {@link AnnotatedElement} (in Java 8).
* javadoc for {@link AnnotatedElement} (in Java 8).
*
* <p>An annotation is <em>meta-present</em> on an element if the annotation
* is declared as a meta-annotation on some other annotation which is
@ -492,9 +492,10 @@ public abstract class AnnotationUtils { @@ -492,9 +492,10 @@ public abstract class AnnotationUtils {
if (annotation != null) {
return annotation;
}
for (Annotation ann : annotatedElement.getDeclaredAnnotations()) {
if (!isInJavaLangAnnotationPackage(ann) && visited.add(ann)) {
annotation = findAnnotation((AnnotatedElement) ann.annotationType(), annotationType, visited);
for (Annotation declaredAnn : annotatedElement.getDeclaredAnnotations()) {
Class<? extends Annotation> declaredType = declaredAnn.annotationType();
if (!isInJavaLangAnnotationPackage(declaredType) && visited.add(declaredAnn)) {
annotation = findAnnotation((AnnotatedElement) declaredType, annotationType, visited);
if (annotation != null) {
return annotation;
}
@ -679,9 +680,10 @@ public abstract class AnnotationUtils { @@ -679,9 +680,10 @@ public abstract class AnnotationUtils {
if (annotation != null) {
return annotation;
}
for (Annotation ann : clazz.getDeclaredAnnotations()) {
if (!isInJavaLangAnnotationPackage(ann) && visited.add(ann)) {
annotation = findAnnotation(ann.annotationType(), annotationType, visited);
for (Annotation declaredAnn : clazz.getDeclaredAnnotations()) {
Class<? extends Annotation> declaredType = declaredAnn.annotationType();
if (!isInJavaLangAnnotationPackage(declaredType) && visited.add(declaredAnn)) {
annotation = findAnnotation(declaredType, annotationType, visited);
if (annotation != null) {
return annotation;
}
@ -816,7 +818,7 @@ public abstract class AnnotationUtils { @@ -816,7 +818,7 @@ public abstract class AnnotationUtils {
* <p>If the supplied {@code clazz} is an interface, only the interface
* itself will be checked. In accordance with standard meta-annotation
* semantics in Java, the inheritance hierarchy for interfaces will not
* be traversed. See the {@linkplain java.lang.annotation.Inherited Javadoc}
* be traversed. See the {@linkplain java.lang.annotation.Inherited javadoc}
* for the {@code @Inherited} meta-annotation for further details regarding
* annotation inheritance.
* @param annotationType the annotation type to look for
@ -868,13 +870,24 @@ public abstract class AnnotationUtils { @@ -868,13 +870,24 @@ public abstract class AnnotationUtils {
* @return {@code true} if the annotation is in the {@code java.lang.annotation} package
*/
public static boolean isInJavaLangAnnotationPackage(Annotation annotation) {
return (annotation != null && isInJavaLangAnnotationPackage(annotation.annotationType().getName()));
return (annotation != null && isInJavaLangAnnotationPackage(annotation.annotationType()));
}
/**
* Determine if the {@link Annotation} with the supplied name is defined
* in the core JDK {@code java.lang.annotation} package.
* @param annotationType the name of the annotation type to check (never {@code null} or empty)
* @param annotationType the annotation type to check
* @return {@code true} if the annotation is in the {@code java.lang.annotation} package
* @since 4.3.8
*/
static boolean isInJavaLangAnnotationPackage(Class<? extends Annotation> annotationType) {
return (annotationType != null && isInJavaLangAnnotationPackage(annotationType.getName()));
}
/**
* Determine if the {@link Annotation} with the supplied name is defined
* in the core JDK {@code java.lang.annotation} package.
* @param annotationType the name of the annotation type to check
* @return {@code true} if the annotation is in the {@code java.lang.annotation} package
* @since 4.2
*/
@ -1519,8 +1532,8 @@ public abstract class AnnotationUtils { @@ -1519,8 +1532,8 @@ public abstract class AnnotationUtils {
* {@linkplain #synthesizeAnnotation(Map, Class, AnnotatedElement)
* synthesized} versions of the maps from the input array.
* @param maps the array of maps of annotation attributes to synthesize
* @param annotationType the type of annotations to synthesize; never
* {@code null}
* @param annotationType the type of annotations to synthesize
* (never {@code null})
* @return a new array of synthesized annotations, or {@code null} if
* the supplied array is {@code null}
* @throws AnnotationConfigurationException if invalid configuration of
@ -1668,8 +1681,8 @@ public abstract class AnnotationUtils { @@ -1668,8 +1681,8 @@ public abstract class AnnotationUtils {
/**
* Get the name of the overridden attribute configured via
* {@link AliasFor @AliasFor} for the supplied annotation {@code attribute}.
* @param attribute the attribute from which to retrieve the override;
* never {@code null}
* @param attribute the attribute from which to retrieve the override
* (never {@code null})
* @param metaAnnotationType the type of meta-annotation in which the
* overridden attribute is allowed to be declared
* @return the name of the overridden attribute, or {@code null} if not
@ -1696,8 +1709,8 @@ public abstract class AnnotationUtils { @@ -1696,8 +1709,8 @@ public abstract class AnnotationUtils {
* match Java's requirements for annotation <em>attributes</em>.
* <p>All methods in the returned list will be
* {@linkplain ReflectionUtils#makeAccessible(Method) made accessible}.
* @param annotationType the type in which to search for attribute methods;
* never {@code null}
* @param annotationType the type in which to search for attribute methods
* (never {@code null})
* @return all annotation attribute methods in the specified annotation
* type (never {@code null}, though potentially <em>empty</em>)
* @since 4.2
@ -1906,7 +1919,7 @@ public abstract class AnnotationUtils { @@ -1906,7 +1919,7 @@ public abstract class AnnotationUtils {
else if (ObjectUtils.nullSafeEquals(this.containerAnnotationType, currentAnnotationType)) {
this.result.addAll(getValue(element, ann));
}
else if (!isInJavaLangAnnotationPackage(ann)) {
else if (!isInJavaLangAnnotationPackage(currentAnnotationType)) {
process(currentAnnotationType);
}
}

9
spring-core/src/main/java/org/springframework/core/type/classreading/AnnotationAttributesReadingVisitor.java

@ -92,17 +92,18 @@ final class AnnotationAttributesReadingVisitor extends RecursiveAnnotationAttrib @@ -92,17 +92,18 @@ final class AnnotationAttributesReadingVisitor extends RecursiveAnnotationAttrib
}
private void recursivelyCollectMetaAnnotations(Set<Annotation> visited, Annotation annotation) {
if (!AnnotationUtils.isInJavaLangAnnotationPackage(annotation) && visited.add(annotation)) {
Class<? extends Annotation> annotationType = annotation.annotationType();
String annotationName = annotationType.getName();
if (!AnnotationUtils.isInJavaLangAnnotationPackage(annotationName) && visited.add(annotation)) {
try {
// Only do attribute scanning for public annotations; we'd run into
// IllegalAccessExceptions otherwise, and we don't want to mess with
// accessibility in a SecurityManager environment.
if (Modifier.isPublic(annotation.annotationType().getModifiers())) {
String annotationName = annotation.annotationType().getName();
if (Modifier.isPublic(annotationType.getModifiers())) {
this.attributesMap.add(annotationName,
AnnotationUtils.getAnnotationAttributes(annotation, false, true));
}
for (Annotation metaMetaAnnotation : annotation.annotationType().getAnnotations()) {
for (Annotation metaMetaAnnotation : annotationType.getAnnotations()) {
recursivelyCollectMetaAnnotations(visited, metaMetaAnnotation);
}
}

22
spring-test/src/main/java/org/springframework/test/util/MetaAnnotationUtils.java

@ -1,5 +1,5 @@ @@ -1,5 +1,5 @@
/*
* Copyright 2002-2016 the original author or authors.
* Copyright 2002-2017 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.
@ -110,13 +110,13 @@ public abstract class MetaAnnotationUtils { @@ -110,13 +110,13 @@ public abstract class MetaAnnotationUtils {
}
// Declared on a composed annotation (i.e., as a meta-annotation)?
for (Annotation composedAnnotation : clazz.getDeclaredAnnotations()) {
if (!AnnotationUtils.isInJavaLangAnnotationPackage(composedAnnotation) && visited.add(composedAnnotation)) {
AnnotationDescriptor<T> descriptor = findAnnotationDescriptor(
composedAnnotation.annotationType(), visited, annotationType);
for (Annotation composedAnn : clazz.getDeclaredAnnotations()) {
Class<? extends Annotation> composedType = composedAnn.annotationType();
if (!AnnotationUtils.isInJavaLangAnnotationPackage(composedType.getName()) && visited.add(composedAnn)) {
AnnotationDescriptor<T> descriptor = findAnnotationDescriptor(composedType, visited, annotationType);
if (descriptor != null) {
return new AnnotationDescriptor<>(
clazz, descriptor.getDeclaringClass(), composedAnnotation, descriptor.getAnnotation());
clazz, descriptor.getDeclaringClass(), composedAnn, descriptor.getAnnotation());
}
}
}
@ -203,8 +203,8 @@ public abstract class MetaAnnotationUtils { @@ -203,8 +203,8 @@ public abstract class MetaAnnotationUtils {
UntypedAnnotationDescriptor descriptor = findAnnotationDescriptorForTypes(
composedAnnotation.annotationType(), visited, annotationTypes);
if (descriptor != null) {
return new UntypedAnnotationDescriptor(clazz, descriptor.getDeclaringClass(), composedAnnotation,
descriptor.getAnnotation());
return new UntypedAnnotationDescriptor(clazz, descriptor.getDeclaringClass(),
composedAnnotation, descriptor.getAnnotation());
}
}
}
@ -214,7 +214,7 @@ public abstract class MetaAnnotationUtils { @@ -214,7 +214,7 @@ public abstract class MetaAnnotationUtils {
UntypedAnnotationDescriptor descriptor = findAnnotationDescriptorForTypes(ifc, visited, annotationTypes);
if (descriptor != null) {
return new UntypedAnnotationDescriptor(clazz, descriptor.getDeclaringClass(),
descriptor.getComposedAnnotation(), descriptor.getAnnotation());
descriptor.getComposedAnnotation(), descriptor.getAnnotation());
}
}
@ -295,8 +295,8 @@ public abstract class MetaAnnotationUtils { @@ -295,8 +295,8 @@ public abstract class MetaAnnotationUtils {
public AnnotationDescriptor(Class<?> rootDeclaringClass, Class<?> declaringClass,
Annotation composedAnnotation, T annotation) {
Assert.notNull(rootDeclaringClass, "rootDeclaringClass must not be null");
Assert.notNull(annotation, "annotation must not be null");
Assert.notNull(rootDeclaringClass, "'rootDeclaringClass' must not be null");
Assert.notNull(annotation, "Annotation must not be null");
this.rootDeclaringClass = rootDeclaringClass;
this.declaringClass = declaringClass;
this.composedAnnotation = composedAnnotation;

Loading…
Cancel
Save