Document "get vs. find" semantics in AnnotatedElementUtils
Issue: SPR-11514
This commit is contained in:
@@ -30,13 +30,59 @@ import org.springframework.util.LinkedMultiValueMap;
|
|||||||
import org.springframework.util.MultiValueMap;
|
import org.springframework.util.MultiValueMap;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Utility class used to collect and merge all annotation attributes on a
|
* General utility methods for working with annotations and meta-annotations
|
||||||
* given {@link AnnotatedElement}, including those declared via meta-annotations.
|
* <em>present</em> on {@link AnnotatedElement AnnotatedElements}.
|
||||||
|
*
|
||||||
|
* <p>{@code AnnotatedElementUtils} defines the public API for Spring's
|
||||||
|
* meta-annotation programming model with support for annotation attribute
|
||||||
|
* overrides. If you do not need support for annotation attribute overrides,
|
||||||
|
* consider using {@link AnnotationUtils} instead.
|
||||||
|
*
|
||||||
|
* <p>Note that the features of this class are not provided by the JDK's
|
||||||
|
* introspection facilities themselves.
|
||||||
|
*
|
||||||
|
* <h3>Annotation Attribute Override Support</h3>
|
||||||
|
* <p>Support for meta-annotations with <em>attribute overrides</em> in
|
||||||
|
* <em>composed annotations</em> is provided by all
|
||||||
|
* {@code getAnnotationAttributes()} and {@code findAnnotationAttributes()}
|
||||||
|
* methods.
|
||||||
|
*
|
||||||
|
* <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
|
||||||
|
* 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 above an {@code AnnotatedElement}.
|
||||||
|
*
|
||||||
|
* <p><strong>Find semantics</strong> are much more exhaustive, providing
|
||||||
|
* <em>get semantics</em> plus support for the following:
|
||||||
|
*
|
||||||
|
* <ul>
|
||||||
|
* <li>Searching on interfaces, if the annotated element is a class
|
||||||
|
* <li>Searching on superclasses, if the annotated element is a class
|
||||||
|
* <li>Resolving bridged methods, if the annotated element is a method
|
||||||
|
* <li>Searching on methods in interfaces, if the annotated element is a method
|
||||||
|
* <li>Searching on methods in superclasses, if the annotated element is a method
|
||||||
|
* </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.
|
||||||
|
* However, methods following <em>find semantics</em> will 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}.
|
||||||
*
|
*
|
||||||
* @author Phillip Webb
|
* @author Phillip Webb
|
||||||
* @author Juergen Hoeller
|
* @author Juergen Hoeller
|
||||||
* @author Sam Brannen
|
* @author Sam Brannen
|
||||||
* @since 4.0
|
* @since 4.0
|
||||||
|
* @see AnnotationUtils
|
||||||
|
* @see AnnotationAttributes
|
||||||
|
* @see BridgeMethodResolver
|
||||||
*/
|
*/
|
||||||
public class AnnotatedElementUtils {
|
public class AnnotatedElementUtils {
|
||||||
|
|
||||||
@@ -44,12 +90,12 @@ public class AnnotatedElementUtils {
|
|||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* <em>Get</em> the fully qualified class names of all meta-annotation
|
* Get the fully qualified class names of all meta-annotation
|
||||||
* types <em>present</em> on the annotation (of the specified
|
* types <em>present</em> on the annotation (of the specified
|
||||||
* {@code annotationType}) on the supplied {@link AnnotatedElement}.
|
* {@code annotationType}) on the supplied {@link AnnotatedElement}.
|
||||||
*
|
*
|
||||||
* <p>This method finds all meta-annotations in the annotation hierarchy
|
* <p>This method follows <em>get semantics</em> as described in the
|
||||||
* above the specified annotation.
|
* {@linkplain AnnotatedElementUtils class-level Javadoc}.
|
||||||
*
|
*
|
||||||
* @param element the annotated element; never {@code null}
|
* @param element the annotated element; never {@code null}
|
||||||
* @param annotationType the annotation type on which to find
|
* @param annotationType the annotation type on which to find
|
||||||
@@ -66,12 +112,12 @@ public class AnnotatedElementUtils {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* <em>Get</em> the fully qualified class names of all meta-annotation
|
* Get the fully qualified class names of all meta-annotation
|
||||||
* types <em>present</em> on the annotation (of the specified
|
* types <em>present</em> on the annotation (of the specified
|
||||||
* {@code annotationType}) on the supplied {@link AnnotatedElement}.
|
* {@code annotationType}) on the supplied {@link AnnotatedElement}.
|
||||||
*
|
*
|
||||||
* <p>This method finds all meta-annotations in the annotation hierarchy
|
* <p>This method follows <em>get semantics</em> as described in the
|
||||||
* above the specified annotation.
|
* {@linkplain AnnotatedElementUtils class-level Javadoc}.
|
||||||
*
|
*
|
||||||
* @param element the annotated element; never {@code null}
|
* @param element the annotated element; never {@code null}
|
||||||
* @param annotationType the fully qualified class name of the annotation
|
* @param annotationType the fully qualified class name of the annotation
|
||||||
@@ -90,7 +136,7 @@ public class AnnotatedElementUtils {
|
|||||||
try {
|
try {
|
||||||
Annotation annotation = getAnnotation(element, annotationType);
|
Annotation annotation = getAnnotation(element, annotationType);
|
||||||
if (annotation != null) {
|
if (annotation != null) {
|
||||||
processWithGetSemantics(annotation.annotationType(), annotationType, new SimpleAnnotationProcessor<Object>() {
|
searchWithGetSemantics(annotation.annotationType(), annotationType, new SimpleAnnotationProcessor<Object>() {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Object process(Annotation annotation, int metaDepth) {
|
public Object process(Annotation annotation, int metaDepth) {
|
||||||
@@ -112,8 +158,8 @@ public class AnnotatedElementUtils {
|
|||||||
* a <em>composed annotation</em> that is meta-annotated with an
|
* a <em>composed annotation</em> that is meta-annotated with an
|
||||||
* annotation of the specified {@code annotationType}.
|
* annotation of the specified {@code annotationType}.
|
||||||
*
|
*
|
||||||
* <p>This method finds all meta-annotations in the annotation hierarchy
|
* <p>This method follows <em>get semantics</em> as described in the
|
||||||
* above the specified element.
|
* {@linkplain AnnotatedElementUtils class-level Javadoc}.
|
||||||
*
|
*
|
||||||
* @param element the annotated element; never {@code null}
|
* @param element the annotated element; never {@code null}
|
||||||
* @param annotationType the fully qualified class name of the meta-annotation
|
* @param annotationType the fully qualified class name of the meta-annotation
|
||||||
@@ -125,7 +171,7 @@ public class AnnotatedElementUtils {
|
|||||||
Assert.notNull(element, "AnnotatedElement must not be null");
|
Assert.notNull(element, "AnnotatedElement must not be null");
|
||||||
Assert.hasText(annotationType, "annotationType must not be null or empty");
|
Assert.hasText(annotationType, "annotationType must not be null or empty");
|
||||||
|
|
||||||
return Boolean.TRUE.equals(processWithGetSemantics(element, annotationType, new SimpleAnnotationProcessor<Boolean>() {
|
return Boolean.TRUE.equals(searchWithGetSemantics(element, annotationType, new SimpleAnnotationProcessor<Boolean>() {
|
||||||
@Override
|
@Override
|
||||||
public Boolean process(Annotation annotation, int metaDepth) {
|
public Boolean process(Annotation annotation, int metaDepth) {
|
||||||
boolean found = annotation.annotationType().getName().equals(annotationType);
|
boolean found = annotation.annotationType().getName().equals(annotationType);
|
||||||
@@ -142,6 +188,9 @@ public class AnnotatedElementUtils {
|
|||||||
* <p>If this method returns {@code true}, then {@link #getAnnotationAttributes}
|
* <p>If this method returns {@code true}, then {@link #getAnnotationAttributes}
|
||||||
* will return a non-null value.
|
* 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 element the annotated element; never {@code null}
|
||||||
* @param annotationType the fully qualified class name of the annotation
|
* @param annotationType the fully qualified class name of the annotation
|
||||||
* type to find; never {@code null} or empty
|
* type to find; never {@code null} or empty
|
||||||
@@ -151,7 +200,7 @@ public class AnnotatedElementUtils {
|
|||||||
Assert.notNull(element, "AnnotatedElement must not be null");
|
Assert.notNull(element, "AnnotatedElement must not be null");
|
||||||
Assert.hasText(annotationType, "annotationType must not be null or empty");
|
Assert.hasText(annotationType, "annotationType must not be null or empty");
|
||||||
|
|
||||||
return Boolean.TRUE.equals(processWithGetSemantics(element, annotationType, new SimpleAnnotationProcessor<Boolean>() {
|
return Boolean.TRUE.equals(searchWithGetSemantics(element, annotationType, new SimpleAnnotationProcessor<Boolean>() {
|
||||||
@Override
|
@Override
|
||||||
public Boolean process(Annotation annotation, int metaDepth) {
|
public Boolean process(Annotation annotation, int metaDepth) {
|
||||||
boolean found = annotation.annotationType().getName().equals(annotationType);
|
boolean found = annotation.annotationType().getName().equals(annotationType);
|
||||||
@@ -161,13 +210,16 @@ public class AnnotatedElementUtils {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* <em>Get</em> annotation attributes of the specified {@code annotationType}
|
* Get annotation attributes of the specified {@code annotationType}
|
||||||
* in the annotation hierarchy of the supplied {@link AnnotatedElement},
|
* in the annotation hierarchy of the supplied {@link AnnotatedElement}
|
||||||
* and merge the results into an {@link AnnotationAttributes} map.
|
* and merge the results into an {@link AnnotationAttributes} map.
|
||||||
*
|
*
|
||||||
* <p>Delegates to {@link #getAnnotationAttributes(AnnotatedElement, String, boolean, boolean)},
|
* <p>Delegates to {@link #getAnnotationAttributes(AnnotatedElement, String, boolean, boolean)},
|
||||||
* supplying {@code false} for {@code classValuesAsString} and {@code nestedAnnotationsAsMap}.
|
* supplying {@code false} for {@code classValuesAsString} and {@code nestedAnnotationsAsMap}.
|
||||||
*
|
*
|
||||||
|
* <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 element the annotated element; never {@code null}
|
||||||
* @param annotationType the fully qualified class name of the annotation
|
* @param annotationType the fully qualified class name of the annotation
|
||||||
* type to find; never {@code null} or empty
|
* type to find; never {@code null} or empty
|
||||||
@@ -180,10 +232,13 @@ public class AnnotatedElementUtils {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* <em>Get</em> annotation attributes of the specified {@code annotationType}
|
* Get annotation attributes of the specified {@code annotationType}
|
||||||
* in the annotation hierarchy of the supplied {@link AnnotatedElement},
|
* in the annotation hierarchy of the supplied {@link AnnotatedElement}
|
||||||
* and merge the results into an {@link AnnotationAttributes} map.
|
* and merge the results into an {@link AnnotationAttributes} map.
|
||||||
*
|
*
|
||||||
|
* <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 element the annotated element; never {@code null}
|
||||||
* @param annotationType the fully qualified class name of the annotation
|
* @param annotationType the fully qualified class name of the annotation
|
||||||
* type to find; never {@code null} or empty
|
* type to find; never {@code null} or empty
|
||||||
@@ -197,25 +252,26 @@ public class AnnotatedElementUtils {
|
|||||||
*/
|
*/
|
||||||
public static AnnotationAttributes getAnnotationAttributes(AnnotatedElement element, String annotationType,
|
public static AnnotationAttributes getAnnotationAttributes(AnnotatedElement element, String annotationType,
|
||||||
boolean classValuesAsString, boolean nestedAnnotationsAsMap) {
|
boolean classValuesAsString, boolean nestedAnnotationsAsMap) {
|
||||||
return processWithGetSemantics(element, annotationType, new MergedAnnotationAttributesProcessor(annotationType,
|
return searchWithGetSemantics(element, annotationType, new MergedAnnotationAttributesProcessor(annotationType,
|
||||||
classValuesAsString, nestedAnnotationsAsMap));
|
classValuesAsString, nestedAnnotationsAsMap));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* <em>Find</em> annotation attributes of the specified {@code annotationType}
|
* Find annotation attributes of the specified {@code annotationType}
|
||||||
* in the annotation hierarchy of the supplied {@link AnnotatedElement},
|
* within annotation hierarchies <em>above</em> the supplied
|
||||||
* and merge the results into an {@link AnnotationAttributes} map.
|
* {@link AnnotatedElement} and merge the results into an
|
||||||
|
* {@link AnnotationAttributes} map.
|
||||||
*
|
*
|
||||||
* <p>If the annotated element is a class, this algorithm will additionally
|
* <p>This method follows <em>find semantics</em> as described in the
|
||||||
* search on interfaces and superclasses.
|
* {@linkplain AnnotatedElementUtils class-level Javadoc}.
|
||||||
* <p>If the annotated element is a method, this algorithm will additionally
|
|
||||||
* search on methods in interfaces and superclasses.
|
|
||||||
*
|
*
|
||||||
* @param element the annotated element; never {@code null}
|
* @param element the annotated element; never {@code null}
|
||||||
* @param annotationType the annotation type to find; never {@code null}
|
* @param annotationType the annotation type to find; never {@code null}
|
||||||
* @return the merged {@code AnnotationAttributes}, or {@code null} if
|
* @return the merged {@code AnnotationAttributes}, or {@code null} if
|
||||||
* not found
|
* not found
|
||||||
* @since 4.2
|
* @since 4.2
|
||||||
|
* @see #findAnnotationAttributes(AnnotatedElement, String)
|
||||||
|
* @see #findAnnotationAttributes(AnnotatedElement, String, boolean, boolean)
|
||||||
*/
|
*/
|
||||||
public static AnnotationAttributes findAnnotationAttributes(AnnotatedElement element,
|
public static AnnotationAttributes findAnnotationAttributes(AnnotatedElement element,
|
||||||
Class<? extends Annotation> annotationType) {
|
Class<? extends Annotation> annotationType) {
|
||||||
@@ -224,14 +280,13 @@ public class AnnotatedElementUtils {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* <em>Find</em> annotation attributes of the specified {@code annotationType}
|
* Find annotation attributes of the specified {@code annotationType}
|
||||||
* in the annotation hierarchy of the supplied {@link AnnotatedElement},
|
* within annotation hierarchies <em>above</em> the supplied
|
||||||
* and merge the results into an {@link AnnotationAttributes} map.
|
* {@link AnnotatedElement} and merge the results into an
|
||||||
|
* {@link AnnotationAttributes} map.
|
||||||
*
|
*
|
||||||
* <p>If the annotated element is a class, this algorithm will additionally
|
* <p>This method follows <em>find semantics</em> as described in the
|
||||||
* search on interfaces and superclasses.
|
* {@linkplain AnnotatedElementUtils class-level Javadoc}.
|
||||||
* <p>If the annotated element is a method, this algorithm will additionally
|
|
||||||
* search on methods in interfaces and superclasses.
|
|
||||||
*
|
*
|
||||||
* @param element the annotated element; never {@code null}
|
* @param element the annotated element; never {@code null}
|
||||||
* @param annotationType the fully qualified class name of the annotation
|
* @param annotationType the fully qualified class name of the annotation
|
||||||
@@ -239,20 +294,21 @@ public class AnnotatedElementUtils {
|
|||||||
* @return the merged {@code AnnotationAttributes}, or {@code null} if
|
* @return the merged {@code AnnotationAttributes}, or {@code null} if
|
||||||
* not found
|
* not found
|
||||||
* @since 4.2
|
* @since 4.2
|
||||||
|
* @see #findAnnotationAttributes(AnnotatedElement, Class)
|
||||||
|
* @see #findAnnotationAttributes(AnnotatedElement, String, boolean, boolean)
|
||||||
*/
|
*/
|
||||||
public static AnnotationAttributes findAnnotationAttributes(AnnotatedElement element, String annotationType) {
|
public static AnnotationAttributes findAnnotationAttributes(AnnotatedElement element, String annotationType) {
|
||||||
return findAnnotationAttributes(element, annotationType, false, false);
|
return findAnnotationAttributes(element, annotationType, false, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* <em>Find</em> annotation attributes of the specified {@code annotationType}
|
* Find annotation attributes of the specified {@code annotationType}
|
||||||
* in the annotation hierarchy of the supplied {@link AnnotatedElement},
|
* within annotation hierarchies <em>above</em> the supplied
|
||||||
* and merge the results into an {@link AnnotationAttributes} map.
|
* {@link AnnotatedElement} and merge the results into an
|
||||||
|
* {@link AnnotationAttributes} map.
|
||||||
*
|
*
|
||||||
* <p>If the annotated element is a class, this algorithm will additionally
|
* <p>This method follows <em>find semantics</em> as described in the
|
||||||
* search on interfaces and superclasses.
|
* {@linkplain AnnotatedElementUtils class-level Javadoc}.
|
||||||
* <p>If the annotated element is a method, this algorithm will additionally
|
|
||||||
* search on methods in interfaces and superclasses.
|
|
||||||
*
|
*
|
||||||
* @param element the annotated element; never {@code null}
|
* @param element the annotated element; never {@code null}
|
||||||
* @param annotationType the fully qualified class name of the annotation
|
* @param annotationType the fully qualified class name of the annotation
|
||||||
@@ -265,6 +321,9 @@ public class AnnotatedElementUtils {
|
|||||||
* @return the merged {@code AnnotationAttributes}, or {@code null} if
|
* @return the merged {@code AnnotationAttributes}, or {@code null} if
|
||||||
* not found
|
* not found
|
||||||
* @since 4.2
|
* @since 4.2
|
||||||
|
* @see #findAnnotationAttributes(AnnotatedElement, Class)
|
||||||
|
* @see #findAnnotationAttributes(AnnotatedElement, String)
|
||||||
|
* @see #getAnnotationAttributes(AnnotatedElement, String, boolean, boolean)
|
||||||
*/
|
*/
|
||||||
public static AnnotationAttributes findAnnotationAttributes(AnnotatedElement element, String annotationType,
|
public static AnnotationAttributes findAnnotationAttributes(AnnotatedElement element, String annotationType,
|
||||||
boolean classValuesAsString, boolean nestedAnnotationsAsMap) {
|
boolean classValuesAsString, boolean nestedAnnotationsAsMap) {
|
||||||
@@ -273,9 +332,10 @@ public class AnnotatedElementUtils {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* <em>Find</em> annotation attributes of the specified {@code annotationType}
|
* Find annotation attributes of the specified {@code annotationType}
|
||||||
* in the annotation hierarchy of the supplied {@link AnnotatedElement},
|
* within annotation hierarchies <em>above</em> the supplied
|
||||||
* and merge the results into an {@link AnnotationAttributes} map.
|
* {@link AnnotatedElement} and merge the results into an
|
||||||
|
* {@link AnnotationAttributes} map.
|
||||||
*
|
*
|
||||||
* @param element the annotated element; never {@code null}
|
* @param element the annotated element; never {@code null}
|
||||||
* @param annotationType the fully qualified class name of the annotation
|
* @param annotationType the fully qualified class name of the annotation
|
||||||
@@ -296,24 +356,29 @@ public class AnnotatedElementUtils {
|
|||||||
* @return the merged {@code AnnotationAttributes}, or {@code null} if
|
* @return the merged {@code AnnotationAttributes}, or {@code null} if
|
||||||
* not found
|
* not found
|
||||||
* @since 4.2
|
* @since 4.2
|
||||||
|
* @see #searchWithFindSemantics
|
||||||
|
* @see MergedAnnotationAttributesProcessor
|
||||||
*/
|
*/
|
||||||
private static AnnotationAttributes findAnnotationAttributes(AnnotatedElement element, String annotationType,
|
private static AnnotationAttributes findAnnotationAttributes(AnnotatedElement element, String annotationType,
|
||||||
boolean searchOnInterfaces, boolean searchOnSuperclasses, boolean searchOnMethodsInInterfaces,
|
boolean searchOnInterfaces, boolean searchOnSuperclasses, boolean searchOnMethodsInInterfaces,
|
||||||
boolean searchOnMethodsInSuperclasses, boolean classValuesAsString, boolean nestedAnnotationsAsMap) {
|
boolean searchOnMethodsInSuperclasses, boolean classValuesAsString, boolean nestedAnnotationsAsMap) {
|
||||||
|
|
||||||
return processWithFindSemantics(element, annotationType, searchOnInterfaces, searchOnSuperclasses,
|
return searchWithFindSemantics(element, annotationType, searchOnInterfaces, searchOnSuperclasses,
|
||||||
searchOnMethodsInInterfaces, searchOnMethodsInSuperclasses, new MergedAnnotationAttributesProcessor(
|
searchOnMethodsInInterfaces, searchOnMethodsInSuperclasses, new MergedAnnotationAttributesProcessor(
|
||||||
annotationType, classValuesAsString, nestedAnnotationsAsMap));
|
annotationType, classValuesAsString, nestedAnnotationsAsMap));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* <em>Get</em> the annotation attributes of <strong>all</strong> annotations
|
* Get the annotation attributes of <strong>all</strong> annotations
|
||||||
* of the specified {@code annotationType} in the annotation hierarchy above
|
* of the specified {@code annotationType} in the annotation hierarchy above
|
||||||
* the supplied {@link AnnotatedElement} and store the results in a
|
* the supplied {@link AnnotatedElement} and store the results in a
|
||||||
* {@link MultiValueMap}.
|
* {@link MultiValueMap}.
|
||||||
*
|
*
|
||||||
* <p>Note: in contrast to {@link #getAnnotationAttributes(AnnotatedElement, String)},
|
* <p>Note: in contrast to {@link #getAnnotationAttributes(AnnotatedElement, String)},
|
||||||
* this method does <em>not</em> take attribute overrides into account.
|
* 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 element the annotated element; never {@code null}
|
||||||
* @param annotationType the fully qualified class name of the annotation
|
* @param annotationType the fully qualified class name of the annotation
|
||||||
@@ -328,13 +393,16 @@ public class AnnotatedElementUtils {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* <em>Get</em> the annotation attributes of <strong>all</strong> annotations
|
* Get the annotation attributes of <strong>all</strong> annotations
|
||||||
* of the specified {@code annotationType} in the annotation hierarchy above
|
* of the specified {@code annotationType} in the annotation hierarchy above
|
||||||
* the supplied {@link AnnotatedElement} and store the results in a
|
* the supplied {@link AnnotatedElement} and store the results in a
|
||||||
* {@link MultiValueMap}.
|
* {@link MultiValueMap}.
|
||||||
*
|
*
|
||||||
* <p>Note: in contrast to {@link #getAnnotationAttributes(AnnotatedElement, String)},
|
* <p>Note: in contrast to {@link #getAnnotationAttributes(AnnotatedElement, String)},
|
||||||
* this method does <em>not</em> take attribute overrides into account.
|
* 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 element the annotated element; never {@code null}
|
||||||
* @param annotationType the fully qualified class name of the annotation
|
* @param annotationType the fully qualified class name of the annotation
|
||||||
@@ -353,7 +421,7 @@ public class AnnotatedElementUtils {
|
|||||||
|
|
||||||
final MultiValueMap<String, Object> attributesMap = new LinkedMultiValueMap<String, Object>();
|
final MultiValueMap<String, Object> attributesMap = new LinkedMultiValueMap<String, Object>();
|
||||||
|
|
||||||
processWithGetSemantics(element, annotationType, new SimpleAnnotationProcessor<Void>() {
|
searchWithGetSemantics(element, annotationType, new SimpleAnnotationProcessor<Void>() {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Void process(Annotation annotation, int metaDepth) {
|
public Void process(Annotation annotation, int metaDepth) {
|
||||||
@@ -375,8 +443,8 @@ public class AnnotatedElementUtils {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Process all annotations of the specified {@code annotationType} and
|
* Search for annotations of the specified {@code annotationType} on
|
||||||
* recursively all meta-annotations on the specified {@code element}.
|
* the specified {@code element}, following <em>get semantics</em>.
|
||||||
*
|
*
|
||||||
* @param element the annotated element; never {@code null}
|
* @param element the annotated element; never {@code null}
|
||||||
* @param annotationType the fully qualified class name of the annotation
|
* @param annotationType the fully qualified class name of the annotation
|
||||||
@@ -384,9 +452,9 @@ public class AnnotatedElementUtils {
|
|||||||
* @param processor the processor to delegate to
|
* @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 processWithGetSemantics(AnnotatedElement element, String annotationType, Processor<T> processor) {
|
private static <T> T searchWithGetSemantics(AnnotatedElement element, String annotationType, Processor<T> processor) {
|
||||||
try {
|
try {
|
||||||
return processWithGetSemantics(element, annotationType, processor, new HashSet<AnnotatedElement>(), 0);
|
return searchWithGetSemantics(element, annotationType, processor, new HashSet<AnnotatedElement>(), 0);
|
||||||
}
|
}
|
||||||
catch (Throwable ex) {
|
catch (Throwable ex) {
|
||||||
throw new IllegalStateException("Failed to introspect annotations on " + element, ex);
|
throw new IllegalStateException("Failed to introspect annotations on " + element, ex);
|
||||||
@@ -394,7 +462,7 @@ public class AnnotatedElementUtils {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Perform the search algorithm for the {@link #processWithGetSemantics}
|
* Perform the search algorithm for the {@link #searchWithGetSemantics}
|
||||||
* method, avoiding endless recursion by tracking which annotated elements
|
* method, avoiding endless recursion by tracking which annotated elements
|
||||||
* have already been <em>visited</em>.
|
* have already been <em>visited</em>.
|
||||||
*
|
*
|
||||||
@@ -410,7 +478,7 @@ public class AnnotatedElementUtils {
|
|||||||
* @param metaDepth the meta-depth of the annotation
|
* @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 processWithGetSemantics(AnnotatedElement element, String annotationType,
|
private static <T> T searchWithGetSemantics(AnnotatedElement element, String annotationType,
|
||||||
Processor<T> processor, Set<AnnotatedElement> visited, int metaDepth) {
|
Processor<T> processor, Set<AnnotatedElement> visited, int metaDepth) {
|
||||||
|
|
||||||
Assert.notNull(element, "AnnotatedElement must not be null");
|
Assert.notNull(element, "AnnotatedElement must not be null");
|
||||||
@@ -435,7 +503,7 @@ public class AnnotatedElementUtils {
|
|||||||
// Search in meta annotations on local annotations
|
// Search in meta annotations on local annotations
|
||||||
for (Annotation annotation : annotations) {
|
for (Annotation annotation : annotations) {
|
||||||
if (!AnnotationUtils.isInJavaLangAnnotationPackage(annotation)) {
|
if (!AnnotationUtils.isInJavaLangAnnotationPackage(annotation)) {
|
||||||
T result = processWithGetSemantics(annotation.annotationType(), annotationType, processor,
|
T result = searchWithGetSemantics(annotation.annotationType(), annotationType, processor,
|
||||||
visited, metaDepth + 1);
|
visited, metaDepth + 1);
|
||||||
if (result != null) {
|
if (result != null) {
|
||||||
processor.postProcess(annotation, result);
|
processor.postProcess(annotation, result);
|
||||||
@@ -453,8 +521,8 @@ public class AnnotatedElementUtils {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Process all annotations of the specified {@code annotationType} and
|
* Search for annotations of the specified {@code annotationType} on
|
||||||
* recursively all meta-annotations on the specified {@code element}.
|
* the specified {@code element}, following <em>find semantics</em>.
|
||||||
*
|
*
|
||||||
* @param element the annotated element; never {@code null}
|
* @param element the annotated element; never {@code null}
|
||||||
* @param annotationType the fully qualified class name of the annotation
|
* @param annotationType the fully qualified class name of the annotation
|
||||||
@@ -470,12 +538,12 @@ public class AnnotatedElementUtils {
|
|||||||
* @param processor the processor to delegate to
|
* @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 processWithFindSemantics(AnnotatedElement element, String annotationType,
|
private static <T> T searchWithFindSemantics(AnnotatedElement element, String annotationType,
|
||||||
boolean searchOnInterfaces, boolean searchOnSuperclasses, boolean searchOnMethodsInInterfaces,
|
boolean searchOnInterfaces, boolean searchOnSuperclasses, boolean searchOnMethodsInInterfaces,
|
||||||
boolean searchOnMethodsInSuperclasses, Processor<T> processor) {
|
boolean searchOnMethodsInSuperclasses, Processor<T> processor) {
|
||||||
|
|
||||||
try {
|
try {
|
||||||
return processWithFindSemantics(element, annotationType, searchOnInterfaces, searchOnSuperclasses,
|
return searchWithFindSemantics(element, annotationType, searchOnInterfaces, searchOnSuperclasses,
|
||||||
searchOnMethodsInInterfaces, searchOnMethodsInSuperclasses, processor, new HashSet<AnnotatedElement>(), 0);
|
searchOnMethodsInInterfaces, searchOnMethodsInSuperclasses, processor, new HashSet<AnnotatedElement>(), 0);
|
||||||
}
|
}
|
||||||
catch (Throwable ex) {
|
catch (Throwable ex) {
|
||||||
@@ -484,7 +552,7 @@ public class AnnotatedElementUtils {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Perform the search algorithm for the {@link #processWithFindSemantics}
|
* Perform the search algorithm for the {@link #searchWithFindSemantics}
|
||||||
* method, avoiding endless recursion by tracking which annotated elements
|
* method, avoiding endless recursion by tracking which annotated elements
|
||||||
* have already been <em>visited</em>.
|
* have already been <em>visited</em>.
|
||||||
*
|
*
|
||||||
@@ -508,7 +576,7 @@ public class AnnotatedElementUtils {
|
|||||||
* @param metaDepth the meta-depth of the annotation
|
* @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 processWithFindSemantics(AnnotatedElement element, String annotationType,
|
private static <T> T searchWithFindSemantics(AnnotatedElement element, String annotationType,
|
||||||
boolean searchOnInterfaces, boolean searchOnSuperclasses, boolean searchOnMethodsInInterfaces,
|
boolean searchOnInterfaces, boolean searchOnSuperclasses, boolean searchOnMethodsInInterfaces,
|
||||||
boolean searchOnMethodsInSuperclasses, Processor<T> processor, Set<AnnotatedElement> visited, int metaDepth) {
|
boolean searchOnMethodsInSuperclasses, Processor<T> processor, Set<AnnotatedElement> visited, int metaDepth) {
|
||||||
|
|
||||||
@@ -536,7 +604,7 @@ public class AnnotatedElementUtils {
|
|||||||
// Search in meta annotations on local annotations
|
// Search in meta annotations on local annotations
|
||||||
for (Annotation annotation : annotations) {
|
for (Annotation annotation : annotations) {
|
||||||
if (!AnnotationUtils.isInJavaLangAnnotationPackage(annotation)) {
|
if (!AnnotationUtils.isInJavaLangAnnotationPackage(annotation)) {
|
||||||
T result = processWithFindSemantics(annotation.annotationType(), annotationType,
|
T result = searchWithFindSemantics(annotation.annotationType(), annotationType,
|
||||||
searchOnInterfaces, searchOnSuperclasses, searchOnMethodsInInterfaces,
|
searchOnInterfaces, searchOnSuperclasses, searchOnMethodsInInterfaces,
|
||||||
searchOnMethodsInSuperclasses, processor, visited, metaDepth + 1);
|
searchOnMethodsInSuperclasses, processor, visited, metaDepth + 1);
|
||||||
if (result != null) {
|
if (result != null) {
|
||||||
@@ -551,7 +619,7 @@ public class AnnotatedElementUtils {
|
|||||||
|
|
||||||
// Search on possibly bridged method
|
// Search on possibly bridged method
|
||||||
Method resolvedMethod = BridgeMethodResolver.findBridgedMethod(method);
|
Method resolvedMethod = BridgeMethodResolver.findBridgedMethod(method);
|
||||||
T result = processWithFindSemantics(resolvedMethod, annotationType, searchOnInterfaces,
|
T result = searchWithFindSemantics(resolvedMethod, annotationType, searchOnInterfaces,
|
||||||
searchOnSuperclasses, searchOnMethodsInInterfaces, searchOnMethodsInSuperclasses, processor,
|
searchOnSuperclasses, searchOnMethodsInInterfaces, searchOnMethodsInSuperclasses, processor,
|
||||||
visited, metaDepth);
|
visited, metaDepth);
|
||||||
if (result != null) {
|
if (result != null) {
|
||||||
@@ -582,7 +650,7 @@ public class AnnotatedElementUtils {
|
|||||||
Method equivalentMethod = clazz.getDeclaredMethod(method.getName(),
|
Method equivalentMethod = clazz.getDeclaredMethod(method.getName(),
|
||||||
method.getParameterTypes());
|
method.getParameterTypes());
|
||||||
Method resolvedEquivalentMethod = BridgeMethodResolver.findBridgedMethod(equivalentMethod);
|
Method resolvedEquivalentMethod = BridgeMethodResolver.findBridgedMethod(equivalentMethod);
|
||||||
result = processWithFindSemantics(resolvedEquivalentMethod, annotationType,
|
result = searchWithFindSemantics(resolvedEquivalentMethod, annotationType,
|
||||||
searchOnInterfaces, searchOnSuperclasses, searchOnMethodsInInterfaces,
|
searchOnInterfaces, searchOnSuperclasses, searchOnMethodsInInterfaces,
|
||||||
searchOnMethodsInSuperclasses, processor, visited, metaDepth);
|
searchOnMethodsInSuperclasses, processor, visited, metaDepth);
|
||||||
if (result != null) {
|
if (result != null) {
|
||||||
@@ -612,7 +680,7 @@ public class AnnotatedElementUtils {
|
|||||||
// Search on interfaces
|
// Search on interfaces
|
||||||
if (searchOnInterfaces) {
|
if (searchOnInterfaces) {
|
||||||
for (Class<?> ifc : clazz.getInterfaces()) {
|
for (Class<?> ifc : clazz.getInterfaces()) {
|
||||||
T result = processWithFindSemantics(ifc, annotationType, searchOnInterfaces,
|
T result = searchWithFindSemantics(ifc, annotationType, searchOnInterfaces,
|
||||||
searchOnSuperclasses, searchOnMethodsInInterfaces, searchOnMethodsInSuperclasses,
|
searchOnSuperclasses, searchOnMethodsInInterfaces, searchOnMethodsInSuperclasses,
|
||||||
processor, visited, metaDepth);
|
processor, visited, metaDepth);
|
||||||
if (result != null) {
|
if (result != null) {
|
||||||
@@ -625,7 +693,7 @@ public class AnnotatedElementUtils {
|
|||||||
if (searchOnSuperclasses) {
|
if (searchOnSuperclasses) {
|
||||||
Class<?> superclass = clazz.getSuperclass();
|
Class<?> superclass = clazz.getSuperclass();
|
||||||
if (superclass != null && !superclass.equals(Object.class)) {
|
if (superclass != null && !superclass.equals(Object.class)) {
|
||||||
T result = processWithFindSemantics(superclass, annotationType, searchOnInterfaces,
|
T result = searchWithFindSemantics(superclass, annotationType, searchOnInterfaces,
|
||||||
searchOnSuperclasses, searchOnMethodsInInterfaces, searchOnMethodsInSuperclasses,
|
searchOnSuperclasses, searchOnMethodsInInterfaces, searchOnMethodsInSuperclasses,
|
||||||
processor, visited, metaDepth);
|
processor, visited, metaDepth);
|
||||||
if (result != null) {
|
if (result != null) {
|
||||||
@@ -650,7 +718,7 @@ public class AnnotatedElementUtils {
|
|||||||
if (AnnotationUtils.isInterfaceWithAnnotatedMethods(iface)) {
|
if (AnnotationUtils.isInterfaceWithAnnotatedMethods(iface)) {
|
||||||
try {
|
try {
|
||||||
Method equivalentMethod = iface.getMethod(method.getName(), method.getParameterTypes());
|
Method equivalentMethod = iface.getMethod(method.getName(), method.getParameterTypes());
|
||||||
T result = processWithFindSemantics(equivalentMethod, annotationType, searchOnInterfaces,
|
T result = searchWithFindSemantics(equivalentMethod, annotationType, searchOnInterfaces,
|
||||||
searchOnSuperclasses, searchOnMethodsInInterfaces, searchOnMethodsInSuperclasses, processor,
|
searchOnSuperclasses, searchOnMethodsInInterfaces, searchOnMethodsInSuperclasses, processor,
|
||||||
visited, metaDepth);
|
visited, metaDepth);
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user