Browse Source

AnnotatedElementUtils consistently operates on actual annotation type if available (for performance reasons)

The goal is to avoid String name comparisons in favor of annotation type identity checks wherever possible. Also, we avoid double getDeclaredAnnotations/getAnnotations checks on anything other than Classes now, since we'd just get the same result in a fresh array.

Issue: SPR-13621
pull/1619/head
Juergen Hoeller 9 years ago
parent
commit
e27df06f91
  1. 473
      spring-core/src/main/java/org/springframework/core/annotation/AnnotatedElementUtils.java

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

@ -53,7 +53,7 @@ import org.springframework.util.MultiValueMap; @@ -53,7 +53,7 @@ import org.springframework.util.MultiValueMap;
*
* <h3>Find vs. Get Semantics</h3>
* <p>The search algorithms used by methods in this class follow either
* <em>find</em> or <em>get</em> semantics. Consult the Javadoc for each
* <em>find</em> or <em>get</em> semantics. Consult the javadocs for each
* individual method for details on which search algorithm is used.
*
* <p><strong>Get semantics</strong> are limited to searching for annotations
@ -98,14 +98,13 @@ public class AnnotatedElementUtils { @@ -98,14 +98,13 @@ public class AnnotatedElementUtils {
/**
* Get the fully qualified class names of all meta-annotation
* types <em>present</em> on the annotation (of the specified
* {@code annotationType}) on the supplied {@link AnnotatedElement}.
* Get the fully qualified class names of all meta-annotation types
* <em>present</em> on the annotation (of the specified {@code annotationType})
* on the supplied {@link AnnotatedElement}.
* <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 on which to find
* meta-annotations; never {@code null}
* {@linkplain AnnotatedElementUtils class-level javadoc}.
* @param element the annotated element
* @param annotationType the annotation type on which to find meta-annotations
* @return the names of all meta-annotations present on the annotation,
* or {@code null} if not found
* @since 4.2
@ -113,8 +112,28 @@ public class AnnotatedElementUtils { @@ -113,8 +112,28 @@ public class AnnotatedElementUtils {
* @see #hasMetaAnnotationTypes
*/
public static Set<String> getMetaAnnotationTypes(AnnotatedElement element, Class<? extends Annotation> annotationType) {
Assert.notNull(element, "AnnotatedElement must not be null");
Assert.notNull(annotationType, "annotationType must not be null");
return getMetaAnnotationTypes(element, annotationType.getName());
final Set<String> types = new LinkedHashSet<String>();
try {
Annotation annotation = element.getAnnotation(annotationType);
if (annotation != null) {
searchWithGetSemantics(annotation.annotationType(), annotationType, null, new SimpleAnnotationProcessor<Object>() {
@Override
public Object process(AnnotatedElement annotatedElement, Annotation annotation, int metaDepth) {
types.add(annotation.annotationType().getName());
return CONTINUE;
}
}, new HashSet<AnnotatedElement>(), 1);
}
}
catch (Throwable ex) {
AnnotationUtils.rethrowAnnotationConfigurationException(ex);
throw new IllegalStateException("Failed to introspect annotations on " + element, ex);
}
return (!types.isEmpty() ? types : null);
}
/**
@ -122,10 +141,10 @@ public class AnnotatedElementUtils { @@ -122,10 +141,10 @@ public class AnnotatedElementUtils {
* types <em>present</em> on the annotation (of the specified
* {@code annotationName}) on the supplied {@link AnnotatedElement}.
* <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}
* {@linkplain AnnotatedElementUtils class-level javadoc}.
* @param element the annotated element
* @param annotationName the fully qualified class name of the annotation
* type on which to find meta-annotations; never {@code null} or empty
* type on which to find meta-annotations
* @return the names of all meta-annotations present on the annotation,
* or {@code null} if not found
* @see #getMetaAnnotationTypes(AnnotatedElement, Class)
@ -134,14 +153,12 @@ public class AnnotatedElementUtils { @@ -134,14 +153,12 @@ public class AnnotatedElementUtils {
public static Set<String> getMetaAnnotationTypes(AnnotatedElement element, String annotationName) {
Assert.notNull(element, "AnnotatedElement must not be null");
Assert.hasLength(annotationName, "annotationName must not be null or empty");
final Set<String> types = new LinkedHashSet<String>();
try {
Annotation annotation = AnnotationUtils.getAnnotation(element, annotationName);
if (annotation != null) {
searchWithGetSemantics(annotation.annotationType(), annotationName, new SimpleAnnotationProcessor<Object>() {
searchWithGetSemantics(annotation.annotationType(), null, annotationName, new SimpleAnnotationProcessor<Object>() {
@Override
public Object process(AnnotatedElement annotatedElement, Annotation annotation, int metaDepth) {
types.add(annotation.annotationType().getName());
@ -163,10 +180,35 @@ public class AnnotatedElementUtils { @@ -163,10 +180,35 @@ public class AnnotatedElementUtils {
* a <em>composed annotation</em> that is meta-annotated with an
* annotation of the specified {@code annotationName}.
* <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 annotationName the fully qualified class name of the meta-annotation
* type to find; never {@code null} or empty
* {@linkplain AnnotatedElementUtils class-level javadoc}.
* @param element the annotated element
* @param annotationType the annotation type on which to find meta-annotations
* @return {@code true} if a matching meta-annotation is present
* @since 4.2.3
* @see #getMetaAnnotationTypes
*/
public static boolean hasMetaAnnotationTypes(AnnotatedElement element, final Class<? extends Annotation> annotationType) {
Assert.notNull(element, "AnnotatedElement must not be null");
Assert.notNull(annotationType, "annotationType must not be null");
return Boolean.TRUE.equals(searchWithGetSemantics(element, annotationType, null, new SimpleAnnotationProcessor<Boolean>() {
@Override
public Boolean process(AnnotatedElement annotatedElement, Annotation annotation, int metaDepth) {
boolean found = (annotation.annotationType() == annotationType);
return (found && metaDepth > 0 ? Boolean.TRUE : CONTINUE);
}
}));
}
/**
* Determine if the supplied {@link AnnotatedElement} is annotated with a
* <em>composed annotation</em> that is meta-annotated with an annotation
* of the specified {@code annotationName}.
* <p>This method follows <em>get semantics</em> as described in the
* {@linkplain AnnotatedElementUtils class-level javadoc}.
* @param element the annotated element
* @param annotationName the fully qualified class name of the
* meta-annotation type to find
* @return {@code true} if a matching meta-annotation is present
* @see #getMetaAnnotationTypes
*/
@ -174,7 +216,7 @@ public class AnnotatedElementUtils { @@ -174,7 +216,7 @@ public class AnnotatedElementUtils {
Assert.notNull(element, "AnnotatedElement must not be null");
Assert.hasLength(annotationName, "annotationName must not be null or empty");
return Boolean.TRUE.equals(searchWithGetSemantics(element, annotationName, new SimpleAnnotationProcessor<Boolean>() {
return Boolean.TRUE.equals(searchWithGetSemantics(element, null, annotationName, new SimpleAnnotationProcessor<Boolean>() {
@Override
public Boolean process(AnnotatedElement annotatedElement, Annotation annotation, int metaDepth) {
boolean found = annotation.annotationType().getName().equals(annotationName);
@ -190,21 +232,42 @@ public class AnnotatedElementUtils { @@ -190,21 +232,42 @@ public class AnnotatedElementUtils {
* <p>If this method returns {@code true}, then {@link #getMergedAnnotationAttributes}
* will return a non-null value.
* <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 annotationName the fully qualified class name of the annotation
* type to find; never {@code null} or empty
* {@linkplain AnnotatedElementUtils class-level javadoc}.
* @param element the annotated element
* @param annotationType the annotation type on which to find meta-annotations
* @return {@code true} if a matching annotation is present
* @since 4.2.3
*/
public static boolean isAnnotated(AnnotatedElement element, final Class<? extends Annotation> annotationType) {
Assert.notNull(element, "AnnotatedElement must not be null");
Assert.notNull(annotationType, "annotationType must not be null");
return Boolean.TRUE.equals(searchWithGetSemantics(element, annotationType, null, new SimpleAnnotationProcessor<Boolean>() {
@Override
public Boolean process(AnnotatedElement annotatedElement, Annotation annotation, int metaDepth) {
boolean found = annotation.annotationType() == annotationType;
return (found ? Boolean.TRUE : CONTINUE);
}
}));
}
/**
* Determine if an annotation of the specified {@code annotationName} is
* <em>present</em> on the supplied {@link AnnotatedElement} or within the
* annotation hierarchy <em>above</em> the specified element.
* <p>If this method returns {@code true}, then {@link #getMergedAnnotationAttributes}
* will return a non-null value.
* <p>This method follows <em>get semantics</em> as described in the
* {@linkplain AnnotatedElementUtils class-level javadoc}.
* @param element the annotated element
* @param annotationName the fully qualified class name of the annotation type to find
* @return {@code true} if a matching annotation is present
*/
public static boolean isAnnotated(AnnotatedElement element, final String annotationName) {
Assert.notNull(element, "AnnotatedElement must not be null");
Assert.hasLength(annotationName, "annotationName must not be null or empty");
if (element.getAnnotations().length == 0) {
return false;
}
return Boolean.TRUE.equals(searchWithGetSemantics(element, annotationName, new SimpleAnnotationProcessor<Boolean>() {
return Boolean.TRUE.equals(searchWithGetSemantics(element, null, annotationName, new SimpleAnnotationProcessor<Boolean>() {
@Override
public Boolean process(AnnotatedElement annotatedElement, Annotation annotation, int metaDepth) {
boolean found = annotation.annotationType().getName().equals(annotationName);
@ -223,8 +286,8 @@ public class AnnotatedElementUtils { @@ -223,8 +286,8 @@ public class AnnotatedElementUtils {
* within a single annotation and within the annotation hierarchy.
* <p>This method delegates to {@link #getMergedAnnotationAttributes(AnnotatedElement, Class)}
* and {@link AnnotationUtils#synthesizeAnnotation(Map, Class, AnnotatedElement)}.
* @param element the annotated element; never {@code null}
* @param annotationType the annotation type to find; never {@code null}
* @param element the annotated element
* @param annotationType the annotation type to find
* @return the merged, synthesized {@code Annotation}, or {@code null} if not found
* @since 4.2
* @see #getMergedAnnotationAttributes(AnnotatedElement, Class)
@ -233,7 +296,7 @@ public class AnnotatedElementUtils { @@ -233,7 +296,7 @@ public class AnnotatedElementUtils {
*/
public static <A extends Annotation> A getMergedAnnotation(AnnotatedElement element, Class<A> annotationType) {
AnnotationAttributes attributes = getMergedAnnotationAttributes(element, annotationType);
return ((attributes != null) ? AnnotationUtils.synthesizeAnnotation(attributes, annotationType, element) : null);
return (attributes != null ? AnnotationUtils.synthesizeAnnotation(attributes, annotationType, element) : null);
}
/**
@ -244,8 +307,8 @@ public class AnnotatedElementUtils { @@ -244,8 +307,8 @@ public class AnnotatedElementUtils {
* <p>{@link AliasFor @AliasFor} semantics are fully supported, both
* within a single annotation and within the annotation hierarchy.
* <p>This method delegates to {@link #getMergedAnnotationAttributes(AnnotatedElement, String)}.
* @param element the annotated element; never {@code null}
* @param annotationType the annotation type to find; never {@code null}
* @param element the annotated element
* @param annotationType the annotation type to find
* @return the merged {@code AnnotationAttributes}, or {@code null} if not found
* @since 4.2
* @see #getMergedAnnotationAttributes(AnnotatedElement, String, boolean, boolean)
@ -253,17 +316,14 @@ public class AnnotatedElementUtils { @@ -253,17 +316,14 @@ public class AnnotatedElementUtils {
* @see #getMergedAnnotation(AnnotatedElement, Class)
* @see #findMergedAnnotation(AnnotatedElement, Class)
*/
public static AnnotationAttributes getMergedAnnotationAttributes(AnnotatedElement element, Class<? extends Annotation> annotationType) {
Assert.notNull(annotationType, "annotationType must not be null");
return getMergedAnnotationAttributes(element, annotationType.getName());
}
public static AnnotationAttributes getMergedAnnotationAttributes(
AnnotatedElement element, Class<? extends Annotation> annotationType) {
/**
* @deprecated As of Spring Framework 4.2, use {@link #getMergedAnnotationAttributes(AnnotatedElement, String)} instead.
*/
@Deprecated
public static AnnotationAttributes getAnnotationAttributes(AnnotatedElement element, String annotationName) {
return getMergedAnnotationAttributes(element, annotationName);
Assert.notNull(annotationType, "annotationType must not be null");
AnnotationAttributes attributes = searchWithGetSemantics(element, annotationType, null,
new MergedAnnotationAttributesProcessor(annotationType, null, false, false));
AnnotationUtils.postProcessAnnotationAttributes(element, attributes, false, false);
return attributes;
}
/**
@ -275,11 +335,9 @@ public class AnnotatedElementUtils { @@ -275,11 +335,9 @@ public class AnnotatedElementUtils {
* within a single annotation and within the annotation hierarchy.
* <p>This method delegates to {@link #getMergedAnnotationAttributes(AnnotatedElement, String, boolean, boolean)},
* supplying {@code false} for {@code classValuesAsString} and {@code nestedAnnotationsAsMap}.
* @param element the annotated element; never {@code null}
* @param annotationName the fully qualified class name of the annotation
* type to find; never {@code null} or empty
* @return the merged {@code AnnotationAttributes}, or {@code null} if
* not found
* @param element the annotated element
* @param annotationName the fully qualified class name of the annotation type to find
* @return the merged {@code AnnotationAttributes}, or {@code null} if not found
* @since 4.2
* @see #getMergedAnnotationAttributes(AnnotatedElement, String, boolean, boolean)
* @see #findMergedAnnotationAttributes(AnnotatedElement, String, boolean, boolean)
@ -290,55 +348,37 @@ public class AnnotatedElementUtils { @@ -290,55 +348,37 @@ public class AnnotatedElementUtils {
return getMergedAnnotationAttributes(element, annotationName, false, false);
}
/**
* @deprecated As of Spring Framework 4.2, use {@link #getMergedAnnotationAttributes(AnnotatedElement, String, boolean, boolean)} instead.
*/
@Deprecated
public static AnnotationAttributes getAnnotationAttributes(AnnotatedElement element, String annotationName,
boolean classValuesAsString, boolean nestedAnnotationsAsMap) {
return getMergedAnnotationAttributes(element, annotationName, classValuesAsString, nestedAnnotationsAsMap);
}
/**
* Get the first annotation of the specified {@code annotationName} within
* the annotation hierarchy <em>above</em> the supplied {@code element} and
* merge that annotation's attributes with <em>matching</em> attributes from
* annotations in lower levels of the annotation hierarchy.
* <p>Attributes from lower levels in the annotation hierarchy override
* attributes of the same name from higher levels, and
* {@link AliasFor @AliasFor} semantics are fully supported, both
* within a single annotation and within the annotation hierarchy.
* <p>In contrast to {@link #getAllAnnotationAttributes}, the search
* algorithm used by this method will stop searching the annotation
* hierarchy once the first annotation of the specified
* {@code annotationName} has been found. As a consequence, additional
* annotations of the specified {@code annotationName} will be ignored.
* <p>Attributes from lower levels in the annotation hierarchy override attributes
* of the same name from higher levels, and {@link AliasFor @AliasFor} semantics are
* fully supported, both within a single annotation and within the annotation hierarchy.
* <p>In contrast to {@link #getAllAnnotationAttributes}, the search algorithm used by
* this method will stop searching the annotation hierarchy once the first annotation
* of the specified {@code annotationName} has been found. As a consequence,
* additional annotations of the specified {@code annotationName} will be ignored.
* <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 annotationName the fully qualified class name of the annotation
* type to find; never {@code null} or empty
* @param classValuesAsString whether to convert Class references into
* Strings or to preserve them as Class references
* @param nestedAnnotationsAsMap whether to convert nested Annotation
* instances into {@code AnnotationAttributes} maps or to preserve them
* as Annotation instances
* @return the merged {@code AnnotationAttributes}, or {@code null} if
* not found
* {@linkplain AnnotatedElementUtils class-level javadoc}.
* @param element the annotated element
* @param annotationName the fully qualified class name of the annotation type to find
* @param classValuesAsString whether to convert Class references into Strings or to
* preserve them as Class references
* @param nestedAnnotationsAsMap whether to convert nested Annotation instances
* into {@code AnnotationAttributes} maps or to preserve them as Annotation instances
* @return the merged {@code AnnotationAttributes}, or {@code null} if not found
* @since 4.2
* @see #findMergedAnnotation(AnnotatedElement, Class)
* @see #findMergedAnnotationAttributes(AnnotatedElement, String, boolean, boolean)
* @see #getAllAnnotationAttributes(AnnotatedElement, String, boolean, boolean)
*/
public static AnnotationAttributes getMergedAnnotationAttributes(AnnotatedElement element, String annotationName,
boolean classValuesAsString, boolean nestedAnnotationsAsMap) {
public static AnnotationAttributes getMergedAnnotationAttributes(AnnotatedElement element,
String annotationName, boolean classValuesAsString, boolean nestedAnnotationsAsMap) {
if (element.getAnnotations().length == 0) {
return null;
}
AnnotationAttributes attributes = searchWithGetSemantics(element, annotationName,
new MergedAnnotationAttributesProcessor(annotationName, classValuesAsString, nestedAnnotationsAsMap));
AnnotationAttributes attributes = searchWithGetSemantics(element, null, annotationName,
new MergedAnnotationAttributesProcessor(null, annotationName, classValuesAsString, nestedAnnotationsAsMap));
AnnotationUtils.postProcessAnnotationAttributes(element, attributes, classValuesAsString, nestedAnnotationsAsMap);
return attributes;
}
@ -352,8 +392,8 @@ public class AnnotatedElementUtils { @@ -352,8 +392,8 @@ public class AnnotatedElementUtils {
* <p>{@link AliasFor @AliasFor} semantics are fully supported, both
* within a single annotation and within the annotation hierarchy.
* <p>This method delegates to {@link #findMergedAnnotation(AnnotatedElement, String)}.
* @param element the annotated element; never {@code null}
* @param annotationType the annotation type to find; never {@code null}
* @param element the annotated element
* @param annotationType the annotation type to find
* @return the merged, synthesized {@code Annotation}, or {@code null} if not found
* @since 4.2
* @see #findMergedAnnotation(AnnotatedElement, String)
@ -376,9 +416,8 @@ public class AnnotatedElementUtils { @@ -376,9 +416,8 @@ public class AnnotatedElementUtils {
* <p>This method delegates to {@link #findMergedAnnotationAttributes(AnnotatedElement, String, boolean, boolean)}
* (supplying {@code false} for {@code classValuesAsString} and {@code nestedAnnotationsAsMap})
* and {@link AnnotationUtils#synthesizeAnnotation(Map, Class, AnnotatedElement)}.
* @param element the annotated element; never {@code null}
* @param annotationName the fully qualified class name of the annotation
* type to find; never {@code null} or empty
* @param element the annotated element
* @param annotationName the fully qualified class name of the annotation type to find
* @return the merged, synthesized {@code Annotation}, or {@code null} if not found
* @since 4.2
* @see #findMergedAnnotation(AnnotatedElement, Class)
@ -407,10 +446,9 @@ public class AnnotatedElementUtils { @@ -407,10 +446,9 @@ public class AnnotatedElementUtils {
* {@code annotationName} has been found. As a consequence, additional
* annotations of the specified {@code annotationName} will be ignored.
* <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 annotationName the fully qualified class name of the annotation
* type to find; never {@code null} or empty
* {@linkplain AnnotatedElementUtils class-level javadoc}.
* @param element the annotated element
* @param annotationType the annotation type to find
* @param classValuesAsString whether to convert Class references into
* Strings or to preserve them as Class references
* @param nestedAnnotationsAsMap whether to convert nested Annotation
@ -421,31 +459,84 @@ public class AnnotatedElementUtils { @@ -421,31 +459,84 @@ public class AnnotatedElementUtils {
* @since 4.2
* @see #findMergedAnnotation(AnnotatedElement, Class)
* @see #getMergedAnnotationAttributes(AnnotatedElement, String, boolean, boolean)
* @deprecated as of 4.2.3; use {@link #findMergedAnnotation(AnnotatedElement, Class)} instead
*/
public static AnnotationAttributes findMergedAnnotationAttributes(AnnotatedElement element, String annotationName,
boolean classValuesAsString, boolean nestedAnnotationsAsMap) {
@Deprecated
public static AnnotationAttributes findMergedAnnotationAttributes(AnnotatedElement element,
Class<? extends Annotation> annotationType, boolean classValuesAsString, boolean nestedAnnotationsAsMap) {
AnnotationAttributes attributes = searchWithFindSemantics(element, annotationName,
new MergedAnnotationAttributesProcessor(annotationName, classValuesAsString, nestedAnnotationsAsMap));
AnnotationAttributes attributes = searchWithFindSemantics(element, annotationType, null,
new MergedAnnotationAttributesProcessor(annotationType, null, classValuesAsString, nestedAnnotationsAsMap));
AnnotationUtils.postProcessAnnotationAttributes(element, attributes, classValuesAsString, nestedAnnotationsAsMap);
return attributes;
}
/**
* Get the annotation attributes of <strong>all</strong> annotations of
* the specified {@code annotationName} in the annotation hierarchy above
* the supplied {@link AnnotatedElement} and store the results in a
* {@link MultiValueMap}.
* Find the first annotation of the specified {@code annotationName} within
* the annotation hierarchy <em>above</em> the supplied {@code element} and
* merge that annotation's attributes with <em>matching</em> attributes from
* annotations in lower levels of the annotation hierarchy.
* <p>Attributes from lower levels in the annotation hierarchy override
* attributes of the same name from higher levels, and
* {@link AliasFor @AliasFor} semantics are fully supported, both
* within a single annotation and within the annotation hierarchy.
* <p>In contrast to {@link #getAllAnnotationAttributes}, the search
* algorithm used by this method will stop searching the annotation
* hierarchy once the first annotation of the specified
* {@code annotationName} has been found. As a consequence, additional
* annotations of the specified {@code annotationName} will be ignored.
* <p>This method follows <em>find semantics</em> as described in the
* {@linkplain AnnotatedElementUtils class-level javadoc}.
* @param element the annotated element
* @param annotationName the fully qualified class name of the annotation type to find
* @param classValuesAsString whether to convert Class references into Strings or to
* preserve them as Class references
* @param nestedAnnotationsAsMap whether to convert nested Annotation instances into
* {@code AnnotationAttributes} maps or to preserve them as Annotation instances
* @return the merged {@code AnnotationAttributes}, or {@code null} if not found
* @since 4.2
* @see #findMergedAnnotation(AnnotatedElement, Class)
* @see #getMergedAnnotationAttributes(AnnotatedElement, String, boolean, boolean)
*/
public static AnnotationAttributes findMergedAnnotationAttributes(AnnotatedElement element,
String annotationName, boolean classValuesAsString, boolean nestedAnnotationsAsMap) {
AnnotationAttributes attributes = searchWithFindSemantics(element, null, annotationName,
new MergedAnnotationAttributesProcessor(null, annotationName, classValuesAsString, nestedAnnotationsAsMap));
AnnotationUtils.postProcessAnnotationAttributes(element, attributes, classValuesAsString, nestedAnnotationsAsMap);
return attributes;
}
/**
* @deprecated As of Spring Framework 4.2, use {@link #getMergedAnnotationAttributes(AnnotatedElement, String)} instead.
*/
@Deprecated
public static AnnotationAttributes getAnnotationAttributes(AnnotatedElement element, String annotationName) {
return getMergedAnnotationAttributes(element, annotationName);
}
/**
* @deprecated As of Spring Framework 4.2, use {@link #getMergedAnnotationAttributes(AnnotatedElement, String, boolean, boolean)} instead.
*/
@Deprecated
public static AnnotationAttributes getAnnotationAttributes(AnnotatedElement element, String annotationName,
boolean classValuesAsString, boolean nestedAnnotationsAsMap) {
return getMergedAnnotationAttributes(element, annotationName, classValuesAsString, nestedAnnotationsAsMap);
}
/**
* Get the annotation attributes of <strong>all</strong> annotations of the specified
* {@code annotationName} in the annotation hierarchy above the supplied
* {@link AnnotatedElement} and store the results in a {@link MultiValueMap}.
* <p>Note: in contrast to {@link #getMergedAnnotationAttributes(AnnotatedElement, String)},
* this method does <em>not</em> support attribute overrides.
* <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 annotationName the fully qualified class name of the annotation
* type to find; never {@code null} or empty
* @return a {@link MultiValueMap} keyed by attribute name, containing
* the annotation attributes from all annotations found, or {@code null}
* if not found
* {@linkplain AnnotatedElementUtils class-level javadoc}.
* @param element the annotated element
* @param annotationName the fully qualified class name of the annotation type to find
* @return a {@link MultiValueMap} keyed by attribute name, containing the annotation
* attributes from all annotations found, or {@code null} if not found
* @see #getAllAnnotationAttributes(AnnotatedElement, String, boolean, boolean)
*/
public static MultiValueMap<String, Object> getAllAnnotationAttributes(AnnotatedElement element, String annotationName) {
@ -460,31 +551,28 @@ public class AnnotatedElementUtils { @@ -460,31 +551,28 @@ public class AnnotatedElementUtils {
* <p>Note: in contrast to {@link #getMergedAnnotationAttributes(AnnotatedElement, String)},
* this method does <em>not</em> support attribute overrides.
* <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 annotationName the fully qualified class name of the annotation
* type to find; never {@code null} or empty
* @param classValuesAsString whether to convert Class references into
* Strings or to preserve them as Class references
* @param nestedAnnotationsAsMap whether to convert nested Annotation
* instances into {@code AnnotationAttributes} maps or to preserve them
* as Annotation instances
* @return a {@link MultiValueMap} keyed by attribute name, containing
* the annotation attributes from all annotations found, or {@code null}
* if not found
* {@linkplain AnnotatedElementUtils class-level javadoc}.
* @param element the annotated element
* @param annotationName the fully qualified class name of the annotation type to find
* @param classValuesAsString whether to convert Class references into Strings or to
* preserve them as Class references
* @param nestedAnnotationsAsMap whether to convert nested Annotation instances into
* {@code AnnotationAttributes} maps or to preserve them as Annotation instances
* @return a {@link MultiValueMap} keyed by attribute name, containing the annotation
* attributes from all annotations found, or {@code null} if not found
*/
public static MultiValueMap<String, Object> getAllAnnotationAttributes(AnnotatedElement element,
final String annotationName, final boolean classValuesAsString, final boolean nestedAnnotationsAsMap) {
final MultiValueMap<String, Object> attributesMap = new LinkedMultiValueMap<String, Object>();
searchWithGetSemantics(element, annotationName, new SimpleAnnotationProcessor<Void>() {
searchWithGetSemantics(element, null, annotationName, new SimpleAnnotationProcessor<Void>() {
@Override
public Void process(AnnotatedElement annotatedElement, Annotation annotation, int metaDepth) {
boolean found = annotation.annotationType().getName().equals(annotationName);
if (found) {
AnnotationAttributes annotationAttributes = AnnotationUtils.getAnnotationAttributes(annotation,
classValuesAsString, nestedAnnotationsAsMap);
AnnotationAttributes annotationAttributes = AnnotationUtils.getAnnotationAttributes(
annotation, classValuesAsString, nestedAnnotationsAsMap);
for (Map.Entry<String, Object> entry : annotationAttributes.entrySet()) {
attributesMap.add(entry.getKey(), entry.getValue());
}
@ -500,15 +588,19 @@ public class AnnotatedElementUtils { @@ -500,15 +588,19 @@ public class AnnotatedElementUtils {
/**
* Search for annotations of the specified {@code annotationName} on
* the specified {@code element}, following <em>get semantics</em>.
* @param element the annotated element; never {@code null}
* @param element the annotated element
* @param annotationType the annotation type on which to find meta-annotations
* @param annotationName the fully qualified class name of the annotation
* type to find; never {@code null} or empty
* 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}
*/
private static <T> T searchWithGetSemantics(AnnotatedElement element, String annotationName, Processor<T> processor) {
private static <T> T searchWithGetSemantics(AnnotatedElement element,
Class<? extends Annotation> annotationType, String annotationName, Processor<T> processor) {
try {
return searchWithGetSemantics(element, annotationName, processor, new HashSet<AnnotatedElement>(), 0);
return searchWithGetSemantics(
element, annotationType, annotationName, processor, new HashSet<AnnotatedElement>(), 0);
}
catch (Throwable ex) {
AnnotationUtils.rethrowAnnotationConfigurationException(ex);
@ -522,42 +614,45 @@ public class AnnotatedElementUtils { @@ -522,42 +614,45 @@ 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
* @param annotationType the annotation type on which to find meta-annotations
* @param annotationName the fully qualified class name of the annotation
* type to find; never {@code null} or empty
* type to find (as an alternative to {@code annotationType})
* @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}
*/
private static <T> T searchWithGetSemantics(AnnotatedElement element, String annotationName,
private static <T> T searchWithGetSemantics(AnnotatedElement element,
Class<? extends Annotation> annotationType, String annotationName,
Processor<T> processor, Set<AnnotatedElement> visited, int metaDepth) {
Assert.notNull(element, "AnnotatedElement must not be null");
Assert.hasLength(annotationName, "annotationName must not be null or empty");
if (visited.add(element)) {
try {
// Start searching within locally declared annotations
List<Annotation> declaredAnnotations = Arrays.asList(element.getDeclaredAnnotations());
T result = searchWithGetSemanticsInAnnotations(element, declaredAnnotations, annotationName, processor,
visited, metaDepth);
T result = searchWithGetSemanticsInAnnotations(element, declaredAnnotations,
annotationType, annotationName, processor, visited, metaDepth);
if (result != null) {
return result;
}
List<Annotation> inheritedAnnotations = new ArrayList<Annotation>();
for (Annotation annotation : element.getAnnotations()) {
if (!declaredAnnotations.contains(annotation)) {
inheritedAnnotations.add(annotation);
if (element instanceof Class) { // otherwise getAnnotations doesn't return anything new
List<Annotation> inheritedAnnotations = new ArrayList<Annotation>();
for (Annotation annotation : element.getAnnotations()) {
if (!declaredAnnotations.contains(annotation)) {
inheritedAnnotations.add(annotation);
}
}
}
// Continue searching within inherited annotations
result = searchWithGetSemanticsInAnnotations(
element, inheritedAnnotations, annotationName, processor, visited, metaDepth);
if (result != null) {
return result;
// Continue searching within inherited annotations
result = searchWithGetSemanticsInAnnotations(element, inheritedAnnotations,
annotationType, annotationName, processor, visited, metaDepth);
if (result != null) {
return result;
}
}
}
catch (Exception ex) {
@ -570,7 +665,7 @@ public class AnnotatedElementUtils { @@ -570,7 +665,7 @@ public class AnnotatedElementUtils {
/**
* This method is invoked by
* {@link #searchWithGetSemantics(AnnotatedElement, String, Processor, Set, int)}
* {@link #searchWithGetSemantics(AnnotatedElement, Class, String, Processor, Set, int)}
* to perform the actual search within the supplied list of annotations.
* <p>This method should be invoked first with locally declared annotations
* and then subsequently with inherited annotations, thereby allowing
@ -579,22 +674,26 @@ public class AnnotatedElementUtils { @@ -579,22 +674,26 @@ public class AnnotatedElementUtils {
* {@link Processor#process process()} method of the {@link Processor} API.
* @param annotatedElement the element that is annotated with the supplied
* annotations, used for contextual logging; may be {@code null} if unknown
* @param annotations the annotations to search in; never {@code null}
* @param annotations the annotations to search in
* @param annotationType the annotation type on which to find meta-annotations
* @param annotationName the fully qualified class name of the annotation
* type to find; never {@code null} or empty
* type to find (as an alternative to {@code annotationType})
* @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}
* @since 4.2
*/
private static <T> T searchWithGetSemanticsInAnnotations(AnnotatedElement annotatedElement, List<Annotation> annotations,
String annotationName, Processor<T> processor, Set<AnnotatedElement> visited, int metaDepth) {
private static <T> T searchWithGetSemanticsInAnnotations(AnnotatedElement annotatedElement,
List<Annotation> annotations, Class<? extends Annotation> annotationType, String annotationName,
Processor<T> processor, Set<AnnotatedElement> visited, int metaDepth) {
// Search in annotations
for (Annotation annotation : annotations) {
if (!AnnotationUtils.isInJavaLangAnnotationPackage(annotation) &&
(annotation.annotationType().getName().equals(annotationName) || metaDepth > 0)) {
((annotationType != null ? annotation.annotationType() == annotationType :
annotation.annotationType().getName().equals(annotationName)) ||
metaDepth > 0)) {
T result = processor.process(annotatedElement, annotation, metaDepth);
if (result != null) {
return result;
@ -605,8 +704,8 @@ public class AnnotatedElementUtils { @@ -605,8 +704,8 @@ public class AnnotatedElementUtils {
// Recursively search in meta-annotations
for (Annotation annotation : annotations) {
if (!AnnotationUtils.isInJavaLangAnnotationPackage(annotation)) {
T result = searchWithGetSemantics(
annotation.annotationType(), annotationName, processor, visited, metaDepth + 1);
T result = searchWithGetSemantics(annotation.annotationType(), annotationType,
annotationName, processor, visited, metaDepth + 1);
if (result != null) {
processor.postProcess(annotatedElement, annotation, result);
return result;
@ -620,16 +719,20 @@ public class AnnotatedElementUtils { @@ -620,16 +719,20 @@ public class AnnotatedElementUtils {
/**
* Search for annotations of the specified {@code annotationName} on
* the specified {@code element}, following <em>find semantics</em>.
* @param element the annotated element; never {@code null}
* @param element the annotated element
* @param annotationType the annotation type on which to find meta-annotations
* @param annotationName the fully qualified class name of the annotation
* type to find; never {@code null} or empty
* 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}
* @since 4.2
*/
private static <T> T searchWithFindSemantics(AnnotatedElement element, String annotationName, Processor<T> processor) {
private static <T> T searchWithFindSemantics(
AnnotatedElement element, Class<? extends Annotation> annotationType, String annotationName, Processor<T> processor) {
try {
return searchWithFindSemantics(element, annotationName, processor, new HashSet<AnnotatedElement>(), 0);
return searchWithFindSemantics(
element, annotationType, annotationName, processor, new HashSet<AnnotatedElement>(), 0);
}
catch (Throwable ex) {
AnnotationUtils.rethrowAnnotationConfigurationException(ex);
@ -643,17 +746,18 @@ public class AnnotatedElementUtils { @@ -643,17 +746,18 @@ 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
* @param annotationType the annotation type on which to find meta-annotations
* @param annotationName the fully qualified class name of the annotation
* type to find; never {@code null} or empty
* type to find (as an alternative to {@code annotationType})
* @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}
* @since 4.2
*/
private static <T> T searchWithFindSemantics(AnnotatedElement element, String annotationName,
Processor<T> processor, Set<AnnotatedElement> visited, int metaDepth) {
private static <T> T searchWithFindSemantics(AnnotatedElement element, Class<? extends Annotation> annotationType,
String annotationName, Processor<T> processor, Set<AnnotatedElement> visited, int metaDepth) {
Assert.notNull(element, "AnnotatedElement must not be null");
Assert.hasLength(annotationName, "annotationName must not be null or empty");
@ -665,8 +769,10 @@ public class AnnotatedElementUtils { @@ -665,8 +769,10 @@ public class AnnotatedElementUtils {
// Search in local annotations
for (Annotation annotation : annotations) {
if (!AnnotationUtils.isInJavaLangAnnotationPackage(annotation)
&& (annotation.annotationType().getName().equals(annotationName) || metaDepth > 0)) {
if (!AnnotationUtils.isInJavaLangAnnotationPackage(annotation) &&
((annotationType != null ? annotation.annotationType() == annotationType :
annotation.annotationType().getName().equals(annotationName)) ||
metaDepth > 0)) {
T result = processor.process(element, annotation, metaDepth);
if (result != null) {
return result;
@ -677,8 +783,8 @@ public class AnnotatedElementUtils { @@ -677,8 +783,8 @@ public class AnnotatedElementUtils {
// Search in meta annotations on local annotations
for (Annotation annotation : annotations) {
if (!AnnotationUtils.isInJavaLangAnnotationPackage(annotation)) {
T result = searchWithFindSemantics(annotation.annotationType(), annotationName, processor,
visited, metaDepth + 1);
T result = searchWithFindSemantics(
annotation.annotationType(), annotationType, annotationName, processor, visited, metaDepth + 1);
if (result != null) {
processor.postProcess(annotation.annotationType(), annotation, result);
return result;
@ -691,14 +797,16 @@ public class AnnotatedElementUtils { @@ -691,14 +797,16 @@ public class AnnotatedElementUtils {
// Search on possibly bridged method
Method resolvedMethod = BridgeMethodResolver.findBridgedMethod(method);
T result = searchWithFindSemantics(resolvedMethod, annotationName, processor, visited, metaDepth);
T result = searchWithFindSemantics(resolvedMethod, annotationType, annotationName,
processor, visited, metaDepth);
if (result != null) {
return result;
}
// Search on methods in interfaces declared locally
Class<?>[] ifcs = method.getDeclaringClass().getInterfaces();
result = searchOnInterfaces(method, annotationName, processor, visited, metaDepth, ifcs);
result = searchOnInterfaces(
method, annotationType, annotationName, processor, visited, metaDepth, ifcs);
if (result != null) {
return result;
}
@ -714,8 +822,8 @@ public class AnnotatedElementUtils { @@ -714,8 +822,8 @@ public class AnnotatedElementUtils {
try {
Method equivalentMethod = clazz.getDeclaredMethod(method.getName(), method.getParameterTypes());
Method resolvedEquivalentMethod = BridgeMethodResolver.findBridgedMethod(equivalentMethod);
result = searchWithFindSemantics(
resolvedEquivalentMethod, annotationName, processor, visited, metaDepth);
result = searchWithFindSemantics(resolvedEquivalentMethod, annotationType, annotationName,
processor, visited, metaDepth);
if (result != null) {
return result;
}
@ -725,8 +833,8 @@ public class AnnotatedElementUtils { @@ -725,8 +833,8 @@ public class AnnotatedElementUtils {
}
// Search on interfaces declared on superclass
result = searchOnInterfaces(method, annotationName, processor, visited, metaDepth,
clazz.getInterfaces());
result = searchOnInterfaces(method, annotationType, annotationName, processor, visited,
metaDepth, clazz.getInterfaces());
if (result != null) {
return result;
}
@ -738,7 +846,8 @@ public class AnnotatedElementUtils { @@ -738,7 +846,8 @@ public class AnnotatedElementUtils {
// Search on interfaces
for (Class<?> ifc : clazz.getInterfaces()) {
T result = searchWithFindSemantics(ifc, annotationName, processor, visited, metaDepth);
T result = searchWithFindSemantics(
ifc, annotationType, annotationName, processor, visited, metaDepth);
if (result != null) {
return result;
}
@ -747,7 +856,8 @@ public class AnnotatedElementUtils { @@ -747,7 +856,8 @@ public class AnnotatedElementUtils {
// Search on superclass
Class<?> superclass = clazz.getSuperclass();
if (superclass != null && Object.class != superclass) {
T result = searchWithFindSemantics(superclass, annotationName, processor, visited, metaDepth);
T result = searchWithFindSemantics(
superclass, annotationType, annotationName, processor, visited, metaDepth);
if (result != null) {
return result;
}
@ -761,14 +871,15 @@ public class AnnotatedElementUtils { @@ -761,14 +871,15 @@ public class AnnotatedElementUtils {
return null;
}
private static <T> T searchOnInterfaces(Method method, String annotationName, Processor<T> processor,
Set<AnnotatedElement> visited, int metaDepth, Class<?>[] ifcs) {
private static <T> T searchOnInterfaces(Method method, Class<? extends Annotation> annotationType, String annotationName,
Processor<T> processor, Set<AnnotatedElement> visited, int metaDepth, Class<?>[] ifcs) {
for (Class<?> iface : ifcs) {
if (AnnotationUtils.isInterfaceWithAnnotatedMethods(iface)) {
try {
Method equivalentMethod = iface.getMethod(method.getName(), method.getParameterTypes());
T result = searchWithFindSemantics(equivalentMethod, annotationName, processor, visited, metaDepth);
T result = searchWithFindSemantics(equivalentMethod, annotationType, annotationName,
processor, visited, metaDepth);
if (result != null) {
return result;
}
@ -871,15 +982,18 @@ public class AnnotatedElementUtils { @@ -871,15 +982,18 @@ public class AnnotatedElementUtils {
*/
private static class MergedAnnotationAttributesProcessor implements Processor<AnnotationAttributes> {
private final Class<? extends Annotation> annotationType;
private final String annotationName;
private final boolean classValuesAsString;
private final boolean nestedAnnotationsAsMap;
MergedAnnotationAttributesProcessor(String annotationName, boolean classValuesAsString,
boolean nestedAnnotationsAsMap) {
MergedAnnotationAttributesProcessor(Class<? extends Annotation> annotationType, String annotationName,
boolean classValuesAsString, boolean nestedAnnotationsAsMap) {
this.annotationType = annotationType;
this.annotationName = annotationName;
this.classValuesAsString = classValuesAsString;
this.nestedAnnotationsAsMap = nestedAnnotationsAsMap;
@ -887,7 +1001,8 @@ public class AnnotatedElementUtils { @@ -887,7 +1001,8 @@ public class AnnotatedElementUtils {
@Override
public AnnotationAttributes process(AnnotatedElement annotatedElement, Annotation annotation, int metaDepth) {
boolean found = annotation.annotationType().getName().equals(this.annotationName);
boolean found = (this.annotationType != null ? annotation.annotationType() == this.annotationType :
annotation.annotationType().getName().equals(this.annotationName));
return (found ? AnnotationUtils.getAnnotationAttributes(annotatedElement, annotation,
this.classValuesAsString, this.nestedAnnotationsAsMap, true) : null);
}

Loading…
Cancel
Save