/*
* Copyright 2002-2019 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.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.core.annotation;
import java.lang.annotation.Annotation;
import java.lang.reflect.AnnotatedElement;
import java.util.Collections;
import java.util.Comparator;
import java.util.LinkedHashSet;
import java.util.Set;
import java.util.stream.Collectors;
import org.springframework.core.BridgeMethodResolver;
import org.springframework.core.annotation.MergedAnnotation.Adapt;
import org.springframework.core.annotation.MergedAnnotations.SearchStrategy;
import org.springframework.lang.Nullable;
import org.springframework.util.MultiValueMap;
General utility methods for finding annotations, meta-annotations, and repeatable annotations on AnnotatedElements
. 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 AnnotationUtils
instead.
Note that the features of this class are not provided by the JDK's
introspection facilities themselves.
Annotation Attribute Overrides
Support for meta-annotations with attribute overrides in
composed annotations is provided by all variants of the getMergedAnnotationAttributes()
, getMergedAnnotation()
, getAllMergedAnnotations()
, getMergedRepeatableAnnotations()
, findMergedAnnotationAttributes()
, findMergedAnnotation()
, findAllMergedAnnotations()
, and findMergedRepeatableAnnotations()
methods.
Find vs. Get Semantics
The search algorithms used by methods in this class follow either
find or get semantics. Consult the javadocs for each
individual method for details on which search algorithm is used.
Get semantics are limited to searching for annotations
that are either present on an AnnotatedElement
(i.e. declared locally or inherited) or declared within the annotation hierarchy above the AnnotatedElement
.
Find semantics are much more exhaustive, providing
get semantics plus support for the following:
- Searching on interfaces, if the annotated element is a class
- Searching on superclasses, if the annotated element is a class
- Resolving bridged methods, if the annotated element is a method
- Searching on methods in interfaces, if the annotated element is a method
- Searching on methods in superclasses, if the annotated element is a method
Support for @Inherited
Methods following get semantics will honor the contract of Java's @Inherited
annotation except that locally declared annotations (including custom composed annotations) will be favored over inherited annotations. In contrast, methods following find semantics will completely ignore the presence of @Inherited
since the find search algorithm manually traverses type and method hierarchies and thereby implicitly supports annotation inheritance without a need for @Inherited
.
Author: Phillip Webb, Juergen Hoeller, Sam Brannen See Also: Since: 4.0
/**
* General utility methods for finding annotations, meta-annotations, and
* repeatable annotations on {@link AnnotatedElement AnnotatedElements}.
*
* <p>{@code AnnotatedElementUtils} defines the public API for Spring's
* meta-annotation programming model with support for <em>annotation attribute
* overrides</em>. 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 Overrides</h3>
* <p>Support for meta-annotations with <em>attribute overrides</em> in
* <em>composed annotations</em> is provided by all variants of the
* {@code getMergedAnnotationAttributes()}, {@code getMergedAnnotation()},
* {@code getAllMergedAnnotations()}, {@code getMergedRepeatableAnnotations()},
* {@code findMergedAnnotationAttributes()}, {@code findMergedAnnotation()},
* {@code findAllMergedAnnotations()}, and {@code findMergedRepeatableAnnotations()}
* 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 javadocs 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 <em>above</em> the {@code AnnotatedElement}.
*
* <p><strong>Find semantics</strong> are much more exhaustive, providing
* <em>get semantics</em> plus support for the following:
*
* <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 except that locally
* declared annotations (including custom composed annotations) will be favored over
* inherited annotations. In contrast, methods following <em>find semantics</em>
* will completely ignore the presence of {@code @Inherited} since the <em>find</em>
* search algorithm manually traverses type and method hierarchies and thereby
* implicitly supports annotation inheritance without a need for {@code @Inherited}.
*
* @author Phillip Webb
* @author Juergen Hoeller
* @author Sam Brannen
* @since 4.0
* @see AliasFor
* @see AnnotationAttributes
* @see AnnotationUtils
* @see BridgeMethodResolver
*/
public abstract class AnnotatedElementUtils {
Build an adapted AnnotatedElement
for the given annotations, typically for use with other methods on AnnotatedElementUtils
. Params: - annotations – the annotations to expose through the
AnnotatedElement
Since: 4.3
/**
* Build an adapted {@link AnnotatedElement} for the given annotations,
* typically for use with other methods on {@link AnnotatedElementUtils}.
* @param annotations the annotations to expose through the {@code AnnotatedElement}
* @since 4.3
*/
public static AnnotatedElement forAnnotations(Annotation... annotations) {
return new AnnotatedElementForAnnotations(annotations);
}
Get the fully qualified class names of all meta-annotation types
present on the annotation (of the specified annotationType
) on the supplied AnnotatedElement
. This method follows get semantics as described in the class-level javadoc.
Params: - element – the annotated element
- annotationType – the annotation type on which to find meta-annotations
See Also: Returns: the names of all meta-annotations present on the annotation,
or an empty set if not found Since: 4.2
/**
* 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
* @param annotationType the annotation type on which to find meta-annotations
* @return the names of all meta-annotations present on the annotation,
* or an empty set if not found
* @since 4.2
* @see #getMetaAnnotationTypes(AnnotatedElement, String)
* @see #hasMetaAnnotationTypes
*/
public static Set<String> getMetaAnnotationTypes(AnnotatedElement element,
Class<? extends Annotation> annotationType) {
return getMetaAnnotationTypes(element, element.getAnnotation(annotationType));
}
Get the fully qualified class names of all meta-annotation
types present on the annotation (of the specified annotationName
) on the supplied AnnotatedElement
. This method follows get semantics as described in the class-level javadoc.
Params: - element – the annotated element
- annotationName – the fully qualified class name of the annotation
type on which to find meta-annotations
See Also: Returns: the names of all meta-annotations present on the annotation,
or an empty set if none found
/**
* Get the fully qualified class names of all meta-annotation
* 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
* @param annotationName the fully qualified class name of the annotation
* type on which to find meta-annotations
* @return the names of all meta-annotations present on the annotation,
* or an empty set if none found
* @see #getMetaAnnotationTypes(AnnotatedElement, Class)
* @see #hasMetaAnnotationTypes
*/
public static Set<String> getMetaAnnotationTypes(AnnotatedElement element, String annotationName) {
for (Annotation annotation : element.getAnnotations()) {
if (annotation.annotationType().getName().equals(annotationName)) {
return getMetaAnnotationTypes(element, annotation);
}
}
return Collections.emptySet();
}
private static Set<String> getMetaAnnotationTypes(AnnotatedElement element, @Nullable Annotation annotation) {
if (annotation == null) {
return Collections.emptySet();
}
return getAnnotations(annotation.annotationType()).stream()
.map(mergedAnnotation -> mergedAnnotation.getType().getName())
.collect(Collectors.toCollection(LinkedHashSet::new));
}
Determine if the supplied AnnotatedElement
is annotated with a composed annotation that is meta-annotated with an annotation of the specified annotationType
. This method follows get semantics as described in the class-level javadoc.
Params: - element – the annotated element
- annotationType – the meta-annotation type to find
See Also: Returns: true
if a matching meta-annotation is presentSince: 4.2.3
/**
* 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 annotationType}.
* <p>This method follows <em>get semantics</em> as described in the
* {@linkplain AnnotatedElementUtils class-level javadoc}.
* @param element the annotated element
* @param annotationType the meta-annotation type to find
* @return {@code true} if a matching meta-annotation is present
* @since 4.2.3
* @see #getMetaAnnotationTypes
*/
public static boolean hasMetaAnnotationTypes(AnnotatedElement element, Class<? extends Annotation> annotationType) {
return getAnnotations(element).stream(annotationType).anyMatch(MergedAnnotation::isMetaPresent);
}
Determine if the supplied AnnotatedElement
is annotated with a composed annotation that is meta-annotated with an annotation of the specified annotationName
. This method follows get semantics as described in the class-level javadoc.
Params: - element – the annotated element
- annotationName – the fully qualified class name of the
meta-annotation type to find
See Also: Returns: true
if a matching meta-annotation is present
/**
* 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
*/
public static boolean hasMetaAnnotationTypes(AnnotatedElement element, String annotationName) {
return getAnnotations(element).stream(annotationName).anyMatch(MergedAnnotation::isMetaPresent);
}
Determine if an annotation of the specified annotationType
is present on the supplied AnnotatedElement
or within the annotation hierarchy above the specified element.
If this method returns true
, then getMergedAnnotationAttributes
will return a non-null value.
This method follows get semantics as described in the class-level javadoc.
Params: - element – the annotated element
- annotationType – the annotation type to find
See Also: Returns: true
if a matching annotation is presentSince: 4.2.3
/**
* Determine if an annotation of the specified {@code annotationType}
* 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 annotationType the annotation type to find
* @return {@code true} if a matching annotation is present
* @since 4.2.3
* @see #hasAnnotation(AnnotatedElement, Class)
*/
public static boolean isAnnotated(AnnotatedElement element, Class<? extends Annotation> annotationType) {
// Shortcut: directly present on the element, with no merging needed?
if (AnnotationFilter.PLAIN.matches(annotationType) ||
AnnotationsScanner.hasPlainJavaAnnotationsOnly(element)) {
return element.isAnnotationPresent(annotationType);
}
// Exhaustive retrieval of merged annotations...
return getAnnotations(element).isPresent(annotationType);
}
Determine if an annotation of the specified annotationName
is present on the supplied AnnotatedElement
or within the annotation hierarchy above the specified element.
If this method returns true
, then getMergedAnnotationAttributes
will return a non-null value.
This method follows get semantics as described in the class-level javadoc.
Params: - element – the annotated element
- annotationName – the fully qualified class name of the annotation type to find
Returns: true
if a matching annotation is present
/**
* 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, String annotationName) {
return getAnnotations(element).isPresent(annotationName);
}
Get the first annotation of the specified annotationType
within the annotation hierarchy above the supplied element
and merge that annotation's attributes with matching attributes from
annotations in lower levels of the annotation hierarchy.
@AliasFor
semantics are fully supported, both within a single annotation and within the annotation hierarchy.
This method delegates to getMergedAnnotationAttributes(AnnotatedElement, String)
.
Params: - element – the annotated element
- annotationType – the annotation type to find
See Also: Returns: the merged AnnotationAttributes
, or null
if not found Since: 4.2
/**
* Get the first annotation of the specified {@code annotationType} 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>{@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
* @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)
* @see #findMergedAnnotationAttributes(AnnotatedElement, String, boolean, boolean)
* @see #getMergedAnnotation(AnnotatedElement, Class)
* @see #findMergedAnnotation(AnnotatedElement, Class)
*/
@Nullable
public static AnnotationAttributes getMergedAnnotationAttributes(
AnnotatedElement element, Class<? extends Annotation> annotationType) {
MergedAnnotation<?> mergedAnnotation = getAnnotations(element)
.get(annotationType, null, MergedAnnotationSelectors.firstDirectlyDeclared());
return getAnnotationAttributes(mergedAnnotation, false, false);
}
Get the first annotation of the specified annotationName
within the annotation hierarchy above the supplied element
and merge that annotation's attributes with matching attributes from
annotations in lower levels of the annotation hierarchy.
@AliasFor
semantics are fully supported, both within a single annotation and within the annotation hierarchy.
This method delegates to getMergedAnnotationAttributes(AnnotatedElement, String, boolean, boolean)
, supplying false
for classValuesAsString
and nestedAnnotationsAsMap
.
Params: - element – the annotated element
- annotationName – the fully qualified class name of the annotation type to find
See Also: Returns: the merged AnnotationAttributes
, or null
if not found Since: 4.2
/**
* 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>{@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, boolean, boolean)},
* supplying {@code false} for {@code classValuesAsString} and {@code nestedAnnotationsAsMap}.
* @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)
* @see #findMergedAnnotation(AnnotatedElement, Class)
* @see #getAllAnnotationAttributes(AnnotatedElement, String)
*/
@Nullable
public static AnnotationAttributes getMergedAnnotationAttributes(AnnotatedElement element,
String annotationName) {
return getMergedAnnotationAttributes(element, annotationName, false, false);
}
Get the first annotation of the specified annotationName
within the annotation hierarchy above the supplied element
and merge that annotation's attributes with matching attributes from
annotations in lower levels of the annotation hierarchy.
Attributes from lower levels in the annotation hierarchy override attributes of the same name from higher levels, and @AliasFor
semantics are fully supported, both within a single annotation and within the annotation hierarchy.
In contrast to getAllAnnotationAttributes
, the search algorithm used by this method will stop searching the annotation hierarchy once the first annotation of the specified annotationName
has been found. As a consequence, additional annotations of the specified annotationName
will be ignored.
This method follows get semantics as described in the class-level javadoc.
Params: - element – the annotated element
- annotationName – the fully qualified class name of the annotation type to find
- classValuesAsString – whether to convert Class references into Strings or to
preserve them as Class references
- nestedAnnotationsAsMap – whether to convert nested Annotation instances into
AnnotationAttributes
maps or to preserve them as Annotation instances
See Also: Returns: the merged AnnotationAttributes
, or null
if not found Since: 4.2
/**
* 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>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
* @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)
*/
@Nullable
public static AnnotationAttributes getMergedAnnotationAttributes(AnnotatedElement element,
String annotationName, boolean classValuesAsString, boolean nestedAnnotationsAsMap) {
MergedAnnotation<?> mergedAnnotation = getAnnotations(element)
.get(annotationName, null, MergedAnnotationSelectors.firstDirectlyDeclared());
return getAnnotationAttributes(mergedAnnotation, classValuesAsString, nestedAnnotationsAsMap);
}
Get the first annotation of the specified annotationType
within the annotation hierarchy above the supplied element
, merge that annotation's attributes with matching attributes from annotations in lower levels of the annotation hierarchy, and synthesize the result back into an annotation of the specified annotationType
. @AliasFor
semantics are fully supported, both within a single annotation and within the annotation hierarchy.
Params: - element – the annotated element
- annotationType – the annotation type to find
See Also: Returns: the merged, synthesized Annotation
, or null
if not found Since: 4.2
/**
* Get the first annotation of the specified {@code annotationType} within
* the annotation hierarchy <em>above</em> the supplied {@code element},
* merge that annotation's attributes with <em>matching</em> attributes from
* annotations in lower levels of the annotation hierarchy, and synthesize
* the result back into an annotation of the specified {@code annotationType}.
* <p>{@link AliasFor @AliasFor} semantics are fully supported, both
* within a single annotation and within the annotation hierarchy.
* @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, Class)
*/
@Nullable
public static <A extends Annotation> A getMergedAnnotation(AnnotatedElement element, Class<A> annotationType) {
// Shortcut: directly present on the element, with no merging needed?
if (AnnotationFilter.PLAIN.matches(annotationType) ||
AnnotationsScanner.hasPlainJavaAnnotationsOnly(element)) {
return element.getDeclaredAnnotation(annotationType);
}
// Exhaustive retrieval of merged annotations...
return getAnnotations(element)
.get(annotationType, null, MergedAnnotationSelectors.firstDirectlyDeclared())
.synthesize(MergedAnnotation::isPresent).orElse(null);
}
Get all annotations of the specified annotationType
within the annotation hierarchy above the supplied element
; and for each annotation found, merge that annotation's attributes with matching attributes from annotations in lower levels of the annotation hierarchy and synthesize the results back into an annotation of the specified annotationType
. @AliasFor
semantics are fully supported, both within a single annotation and within annotation hierarchies.
This method follows get semantics as described in the class-level javadoc.
Params: - element – the annotated element (never
null
) - annotationType – the annotation type to find (never
null
)
See Also: Returns: the set of all merged, synthesized Annotations
found, or an empty set if none were found Since: 4.3
/**
* Get <strong>all</strong> annotations of the specified {@code annotationType}
* within the annotation hierarchy <em>above</em> the supplied {@code element};
* and for each annotation found, merge that annotation's attributes with
* <em>matching</em> attributes from annotations in lower levels of the annotation
* hierarchy and synthesize the results back into an annotation of the specified
* {@code annotationType}.
* <p>{@link AliasFor @AliasFor} semantics are fully supported, both within a
* 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
* @since 4.3
* @see #getMergedAnnotation(AnnotatedElement, Class)
* @see #getAllAnnotationAttributes(AnnotatedElement, String)
* @see #findAllMergedAnnotations(AnnotatedElement, Class)
*/
public static <A extends Annotation> Set<A> getAllMergedAnnotations(
AnnotatedElement element, Class<A> annotationType) {
return getAnnotations(element).stream(annotationType)
.collect(MergedAnnotationCollectors.toAnnotationSet());
}
Get all annotations of the specified annotationTypes
within the annotation hierarchy above the supplied element
; and for each annotation found, merge that annotation's attributes with matching attributes from annotations in lower levels of the annotation hierarchy and synthesize the results back into an annotation of the corresponding annotationType
. @AliasFor
semantics are fully supported, both within a single annotation and within annotation hierarchies.
This method follows get semantics as described in the class-level javadoc.
Params: - element – the annotated element (never
null
) - annotationTypes – the annotation types to find
See Also: Returns: the set of all merged, synthesized Annotations
found, or an empty set if none were found Since: 5.1
/**
* Get <strong>all</strong> annotations of the specified {@code annotationTypes}
* within the annotation hierarchy <em>above</em> the supplied {@code element};
* and for each annotation found, merge that annotation's attributes with
* <em>matching</em> attributes from annotations in lower levels of the
* annotation hierarchy and synthesize the results back into an annotation
* of the corresponding {@code annotationType}.
* <p>{@link AliasFor @AliasFor} semantics are fully supported, both within a
* 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 annotationTypes the annotation types to find
* @return the set of all merged, synthesized {@code Annotations} found,
* or an empty set if none were found
* @since 5.1
* @see #getAllMergedAnnotations(AnnotatedElement, Class)
*/
public static Set<Annotation> getAllMergedAnnotations(AnnotatedElement element,
Set<Class<? extends Annotation>> annotationTypes) {
return getAnnotations(element).stream()
.filter(MergedAnnotationPredicates.typeIn(annotationTypes))
.collect(MergedAnnotationCollectors.toAnnotationSet());
}
Get all repeatable annotations of the specified annotationType
within the annotation hierarchy above the supplied element
; and for each annotation found, merge that annotation's attributes with matching attributes from annotations in lower levels of the annotation hierarchy and synthesize the results back into an annotation of the specified annotationType
. The container type that holds the repeatable annotations will be looked up via Repeatable
.
@AliasFor
semantics are fully supported, both within a single annotation and within annotation hierarchies.
This method follows get semantics as described in the class-level javadoc.
Params: - element – the annotated element (never
null
) - annotationType – the annotation type to find (never
null
)
Throws: - IllegalArgumentException – if the
element
or annotationType
is null
, or if the container type cannot be resolved
See Also: Returns: the set of all merged repeatable Annotations
found, or an empty set if none were found Since: 4.3
/**
* Get all <em>repeatable annotations</em> of the specified {@code annotationType}
* within the annotation hierarchy <em>above</em> the supplied {@code element};
* and for each annotation found, merge that annotation's attributes with
* <em>matching</em> attributes from annotations in lower levels of the annotation
* hierarchy and synthesize the results back into an annotation of the specified
* {@code annotationType}.
* <p>The container type that holds the repeatable annotations will be looked up
* via {@link java.lang.annotation.Repeatable}.
* <p>{@link AliasFor @AliasFor} semantics are fully supported, both within a
* 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
* @throws IllegalArgumentException if the {@code element} or {@code annotationType}
* is {@code null}, or if the container type cannot be resolved
* @since 4.3
* @see #getMergedAnnotation(AnnotatedElement, Class)
* @see #getAllMergedAnnotations(AnnotatedElement, Class)
* @see #getMergedRepeatableAnnotations(AnnotatedElement, Class, Class)
*/
public static <A extends Annotation> Set<A> getMergedRepeatableAnnotations(
AnnotatedElement element, Class<A> annotationType) {
return getMergedRepeatableAnnotations(element, annotationType, null);
}
Get all repeatable annotations of the specified annotationType
within the annotation hierarchy above the supplied element
; and for each annotation found, merge that annotation's attributes with matching attributes from annotations in lower levels of the annotation hierarchy and synthesize the results back into an annotation of the specified annotationType
. @AliasFor
semantics are fully supported, both within a single annotation and within annotation hierarchies.
This method follows get semantics as described in the class-level javadoc.
Params: - element – the annotated element (never
null
) - annotationType – the annotation type to find (never
null
) - containerType – the type of the container that holds the annotations; may be
null
if the container type should be looked up via Repeatable
Throws: - IllegalArgumentException – if the
element
or annotationType
is null
, or if the container type cannot be resolved - AnnotationConfigurationException – if the supplied
containerType
is not a valid container annotation for the supplied annotationType
See Also: Returns: the set of all merged repeatable Annotations
found, or an empty set if none were found Since: 4.3
/**
* Get all <em>repeatable annotations</em> of the specified {@code annotationType}
* within the annotation hierarchy <em>above</em> the supplied {@code element};
* and for each annotation found, merge that annotation's attributes with
* <em>matching</em> attributes from annotations in lower levels of the annotation
* hierarchy and synthesize the results back into an annotation of the specified
* {@code annotationType}.
* <p>{@link AliasFor @AliasFor} semantics are fully supported, both within a
* 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 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
* @throws IllegalArgumentException if the {@code element} or {@code annotationType}
* is {@code null}, or if the container type cannot be resolved
* @throws AnnotationConfigurationException if the supplied {@code containerType}
* is not a valid container annotation for the supplied {@code annotationType}
* @since 4.3
* @see #getMergedAnnotation(AnnotatedElement, Class)
* @see #getAllMergedAnnotations(AnnotatedElement, Class)
*/
public static <A extends Annotation> Set<A> getMergedRepeatableAnnotations(
AnnotatedElement element, Class<A> annotationType,
@Nullable Class<? extends Annotation> containerType) {
return getRepeatableAnnotations(element, containerType, annotationType)
.stream(annotationType)
.collect(MergedAnnotationCollectors.toAnnotationSet());
}
Get the annotation attributes of all annotations of the specified annotationName
in the annotation hierarchy above the supplied AnnotatedElement
and store the results in a MultiValueMap
. Note: in contrast to getMergedAnnotationAttributes(AnnotatedElement, String)
, this method does not support attribute overrides.
This method follows get semantics as described in the class-level javadoc.
Params: - element – the annotated element
- annotationName – the fully qualified class name of the annotation type to find
See Also: Returns: a MultiValueMap
keyed by attribute name, containing the annotation attributes from all annotations found, or null
if not found
/**
* 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
* @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)
*/
@Nullable
public static MultiValueMap<String, Object> getAllAnnotationAttributes(
AnnotatedElement element, String annotationName) {
return getAllAnnotationAttributes(element, annotationName, false, false);
}
Get the annotation attributes of all annotations of the specified annotationName
in the annotation hierarchy above the supplied AnnotatedElement
and store the results in a MultiValueMap
. Note: in contrast to getMergedAnnotationAttributes(AnnotatedElement, String)
, this method does not support attribute overrides.
This method follows get semantics as described in the class-level javadoc.
Params: - element – the annotated element
- annotationName – the fully qualified class name of the annotation type to find
- classValuesAsString – whether to convert Class references into Strings or to
preserve them as Class references
- nestedAnnotationsAsMap – whether to convert nested Annotation instances into
AnnotationAttributes
maps or to preserve them as Annotation instances
Returns: a MultiValueMap
keyed by attribute name, containing the annotation attributes from all annotations found, or null
if not found
/**
* 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
* @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
*/
@Nullable
public static MultiValueMap<String, Object> getAllAnnotationAttributes(AnnotatedElement element,
String annotationName, final boolean classValuesAsString, final boolean nestedAnnotationsAsMap) {
Adapt[] adaptations = Adapt.values(classValuesAsString, nestedAnnotationsAsMap);
return getAnnotations(element).stream(annotationName)
.filter(MergedAnnotationPredicates.unique(MergedAnnotation::getMetaTypes))
.map(MergedAnnotation::withNonMergedAttributes)
.collect(MergedAnnotationCollectors.toMultiValueMap(AnnotatedElementUtils::nullIfEmpty, adaptations));
}
Determine if an annotation of the specified annotationType
is available on the supplied AnnotatedElement
or within the annotation hierarchy above the specified element.
If this method returns true
, then findMergedAnnotationAttributes
will return a non-null value.
This method follows find semantics as described in the class-level javadoc.
Params: - element – the annotated element
- annotationType – the annotation type to find
See Also: Returns: true
if a matching annotation is presentSince: 4.3
/**
* Determine if an annotation of the specified {@code annotationType}
* is <em>available</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 #findMergedAnnotationAttributes}
* will return a non-null value.
* <p>This method follows <em>find semantics</em> as described in the
* {@linkplain AnnotatedElementUtils class-level javadoc}.
* @param element the annotated element
* @param annotationType the annotation type to find
* @return {@code true} if a matching annotation is present
* @since 4.3
* @see #isAnnotated(AnnotatedElement, Class)
*/
public static boolean hasAnnotation(AnnotatedElement element, Class<? extends Annotation> annotationType) {
// Shortcut: directly present on the element, with no merging needed?
if (AnnotationFilter.PLAIN.matches(annotationType) ||
AnnotationsScanner.hasPlainJavaAnnotationsOnly(element)) {
return element.isAnnotationPresent(annotationType);
}
// Exhaustive retrieval of merged annotations...
return findAnnotations(element).isPresent(annotationType);
}
Find the first annotation of the specified annotationType
within the annotation hierarchy above the supplied element
and merge that annotation's attributes with matching attributes from
annotations in lower levels of the annotation hierarchy.
Attributes from lower levels in the annotation hierarchy override attributes of the same name from higher levels, and @AliasFor
semantics are fully supported, both within a single annotation and within the annotation hierarchy.
In contrast to getAllAnnotationAttributes
, the search algorithm used by this method will stop searching the annotation hierarchy once the first annotation of the specified annotationType
has been found. As a consequence, additional annotations of the specified annotationType
will be ignored.
This method follows find semantics as described in the class-level javadoc.
Params: - element – the annotated element
- annotationType – the annotation type to find
- classValuesAsString – whether to convert Class references into
Strings or to preserve them as Class references
- nestedAnnotationsAsMap – whether to convert nested Annotation instances into
AnnotationAttributes
maps or to preserve them as Annotation instances
See Also: Returns: the merged AnnotationAttributes
, or null
if not found Since: 4.2
/**
* Find the first annotation of the specified {@code annotationType} 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 annotationType} has been found.
* As a consequence, additional annotations of the specified
* {@code annotationType} 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 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 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)
*/
@Nullable
public static AnnotationAttributes findMergedAnnotationAttributes(AnnotatedElement element,
Class<? extends Annotation> annotationType, boolean classValuesAsString, boolean nestedAnnotationsAsMap) {
MergedAnnotation<?> mergedAnnotation = findAnnotations(element)
.get(annotationType, null, MergedAnnotationSelectors.firstDirectlyDeclared());
return getAnnotationAttributes(mergedAnnotation, classValuesAsString, nestedAnnotationsAsMap);
}
Find the first annotation of the specified annotationName
within the annotation hierarchy above the supplied element
and merge that annotation's attributes with matching attributes from
annotations in lower levels of the annotation hierarchy.
Attributes from lower levels in the annotation hierarchy override attributes of the same name from higher levels, and @AliasFor
semantics are fully supported, both within a single annotation and within the annotation hierarchy.
In contrast to getAllAnnotationAttributes
, the search algorithm used by this method will stop searching the annotation hierarchy once the first annotation of the specified annotationName
has been found. As a consequence, additional annotations of the specified annotationName
will be ignored.
This method follows find semantics as described in the class-level javadoc.
Params: - element – the annotated element
- annotationName – the fully qualified class name of the annotation type to find
- classValuesAsString – whether to convert Class references into Strings or to
preserve them as Class references
- nestedAnnotationsAsMap – whether to convert nested Annotation instances into
AnnotationAttributes
maps or to preserve them as Annotation instances
See Also: Returns: the merged AnnotationAttributes
, or null
if not found Since: 4.2
/**
* 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)
*/
@Nullable
public static AnnotationAttributes findMergedAnnotationAttributes(AnnotatedElement element,
String annotationName, boolean classValuesAsString, boolean nestedAnnotationsAsMap) {
MergedAnnotation<?> mergedAnnotation = findAnnotations(element)
.get(annotationName, null, MergedAnnotationSelectors.firstDirectlyDeclared());
return getAnnotationAttributes(mergedAnnotation, classValuesAsString, nestedAnnotationsAsMap);
}
Find the first annotation of the specified annotationType
within the annotation hierarchy above the supplied element
, merge that annotation's attributes with matching attributes from annotations in lower levels of the annotation hierarchy, and synthesize the result back into an annotation of the specified annotationType
. @AliasFor
semantics are fully supported, both within a single annotation and within the annotation hierarchy.
This method follows find semantics as described in the class-level javadoc.
Params: - element – the annotated element
- annotationType – the annotation type to find
See Also: Returns: the merged, synthesized Annotation
, or null
if not found Since: 4.2
/**
* Find the first annotation of the specified {@code annotationType} within
* the annotation hierarchy <em>above</em> the supplied {@code element},
* merge that annotation's attributes with <em>matching</em> attributes from
* annotations in lower levels of the annotation hierarchy, and synthesize
* the result back into an annotation of the specified {@code annotationType}.
* <p>{@link AliasFor @AliasFor} semantics are fully supported, both
* within a single annotation and within the annotation hierarchy.
* <p>This method follows <em>find semantics</em> as described in the
* {@linkplain AnnotatedElementUtils class-level javadoc}.
* @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 #findAllMergedAnnotations(AnnotatedElement, Class)
* @see #findMergedAnnotationAttributes(AnnotatedElement, String, boolean, boolean)
* @see #getMergedAnnotationAttributes(AnnotatedElement, Class)
*/
@Nullable
public static <A extends Annotation> A findMergedAnnotation(AnnotatedElement element, Class<A> annotationType) {
// Shortcut: directly present on the element, with no merging needed?
if (AnnotationFilter.PLAIN.matches(annotationType) ||
AnnotationsScanner.hasPlainJavaAnnotationsOnly(element)) {
return element.getDeclaredAnnotation(annotationType);
}
// Exhaustive retrieval of merged annotations...
return findAnnotations(element)
.get(annotationType, null, MergedAnnotationSelectors.firstDirectlyDeclared())
.synthesize(MergedAnnotation::isPresent).orElse(null);
}
Find all annotations of the specified annotationType
within the annotation hierarchy above the supplied element
; and for each annotation found, merge that annotation's attributes with matching attributes from annotations in lower levels of the annotation hierarchy and synthesize the results back into an annotation of the specified annotationType
. @AliasFor
semantics are fully supported, both within a single annotation and within annotation hierarchies.
This method follows find semantics as described in the class-level javadoc.
Params: - element – the annotated element (never
null
) - annotationType – the annotation type to find (never
null
)
See Also: Returns: the set of all merged, synthesized Annotations
found, or an empty set if none were found Since: 4.3
/**
* Find <strong>all</strong> annotations of the specified {@code annotationType}
* within the annotation hierarchy <em>above</em> the supplied {@code element};
* and for each annotation found, merge that annotation's attributes with
* <em>matching</em> attributes from annotations in lower levels of the annotation
* hierarchy and synthesize the results back into an annotation of the specified
* {@code annotationType}.
* <p>{@link AliasFor @AliasFor} semantics are fully supported, both within a
* 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
* @since 4.3
* @see #findMergedAnnotation(AnnotatedElement, Class)
* @see #getAllMergedAnnotations(AnnotatedElement, Class)
*/
public static <A extends Annotation> Set<A> findAllMergedAnnotations(AnnotatedElement element, Class<A> annotationType) {
return findAnnotations(element).stream(annotationType)
.sorted(highAggregateIndexesFirst())
.collect(MergedAnnotationCollectors.toAnnotationSet());
}
Find all annotations of the specified annotationTypes
within the annotation hierarchy above the supplied element
; and for each annotation found, merge that annotation's attributes with matching attributes from annotations in lower levels of the annotation hierarchy and synthesize the results back into an annotation of the corresponding annotationType
. @AliasFor
semantics are fully supported, both within a single annotation and within annotation hierarchies.
This method follows find semantics as described in the class-level javadoc.
Params: - element – the annotated element (never
null
) - annotationTypes – the annotation types to find
See Also: Returns: the set of all merged, synthesized Annotations
found, or an empty set if none were found Since: 5.1
/**
* Find <strong>all</strong> annotations of the specified {@code annotationTypes}
* within the annotation hierarchy <em>above</em> the supplied {@code element};
* and for each annotation found, merge that annotation's attributes with
* <em>matching</em> attributes from annotations in lower levels of the
* annotation hierarchy and synthesize the results back into an annotation
* of the corresponding {@code annotationType}.
* <p>{@link AliasFor @AliasFor} semantics are fully supported, both within a
* 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 annotationTypes the annotation types to find
* @return the set of all merged, synthesized {@code Annotations} found,
* or an empty set if none were found
* @since 5.1
* @see #findAllMergedAnnotations(AnnotatedElement, Class)
*/
public static Set<Annotation> findAllMergedAnnotations(AnnotatedElement element, Set<Class<? extends Annotation>> annotationTypes) {
return findAnnotations(element).stream()
.filter(MergedAnnotationPredicates.typeIn(annotationTypes))
.sorted(highAggregateIndexesFirst())
.collect(MergedAnnotationCollectors.toAnnotationSet());
}
Find all repeatable annotations of the specified annotationType
within the annotation hierarchy above the supplied element
; and for each annotation found, merge that annotation's attributes with matching attributes from annotations in lower levels of the annotation hierarchy and synthesize the results back into an annotation of the specified annotationType
. The container type that holds the repeatable annotations will be looked up via Repeatable
.
@AliasFor
semantics are fully supported, both within a single annotation and within annotation hierarchies.
This method follows find semantics as described in the class-level javadoc.
Params: - element – the annotated element (never
null
) - annotationType – the annotation type to find (never
null
)
Throws: - IllegalArgumentException – if the
element
or annotationType
is null
, or if the container type cannot be resolved
See Also: Returns: the set of all merged repeatable Annotations
found, or an empty set if none were found Since: 4.3
/**
* Find all <em>repeatable annotations</em> of the specified {@code annotationType}
* within the annotation hierarchy <em>above</em> the supplied {@code element};
* and for each annotation found, merge that annotation's attributes with
* <em>matching</em> attributes from annotations in lower levels of the annotation
* hierarchy and synthesize the results back into an annotation of the specified
* {@code annotationType}.
* <p>The container type that holds the repeatable annotations will be looked up
* via {@link java.lang.annotation.Repeatable}.
* <p>{@link AliasFor @AliasFor} semantics are fully supported, both within a
* 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
* @throws IllegalArgumentException if the {@code element} or {@code annotationType}
* is {@code null}, or if the container type cannot be resolved
* @since 4.3
* @see #findMergedAnnotation(AnnotatedElement, Class)
* @see #findAllMergedAnnotations(AnnotatedElement, Class)
* @see #findMergedRepeatableAnnotations(AnnotatedElement, Class, Class)
*/
public static <A extends Annotation> Set<A> findMergedRepeatableAnnotations(AnnotatedElement element,
Class<A> annotationType) {
return findMergedRepeatableAnnotations(element, annotationType, null);
}
Find all repeatable annotations of the specified annotationType
within the annotation hierarchy above the supplied element
; and for each annotation found, merge that annotation's attributes with matching attributes from annotations in lower levels of the annotation hierarchy and synthesize the results back into an annotation of the specified annotationType
. @AliasFor
semantics are fully supported, both within a single annotation and within annotation hierarchies.
This method follows find semantics as described in the class-level javadoc.
Params: - element – the annotated element (never
null
) - annotationType – the annotation type to find (never
null
) - containerType – the type of the container that holds the annotations; may be
null
if the container type should be looked up via Repeatable
Throws: - IllegalArgumentException – if the
element
or annotationType
is null
, or if the container type cannot be resolved - AnnotationConfigurationException – if the supplied
containerType
is not a valid container annotation for the supplied annotationType
See Also: Returns: the set of all merged repeatable Annotations
found, or an empty set if none were found Since: 4.3
/**
* Find all <em>repeatable annotations</em> of the specified {@code annotationType}
* within the annotation hierarchy <em>above</em> the supplied {@code element};
* and for each annotation found, merge that annotation's attributes with
* <em>matching</em> attributes from annotations in lower levels of the annotation
* hierarchy and synthesize the results back into an annotation of the specified
* {@code annotationType}.
* <p>{@link AliasFor @AliasFor} semantics are fully supported, both within a
* 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 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
* @throws IllegalArgumentException if the {@code element} or {@code annotationType}
* is {@code null}, or if the container type cannot be resolved
* @throws AnnotationConfigurationException if the supplied {@code containerType}
* is not a valid container annotation for the supplied {@code annotationType}
* @since 4.3
* @see #findMergedAnnotation(AnnotatedElement, Class)
* @see #findAllMergedAnnotations(AnnotatedElement, Class)
*/
public static <A extends Annotation> Set<A> findMergedRepeatableAnnotations(AnnotatedElement element,
Class<A> annotationType, @Nullable Class<? extends Annotation> containerType) {
return findRepeatableAnnotations(element, containerType, annotationType)
.stream(annotationType)
.sorted(highAggregateIndexesFirst())
.collect(MergedAnnotationCollectors.toAnnotationSet());
}
private static MergedAnnotations getAnnotations(AnnotatedElement element) {
return MergedAnnotations.from(element, SearchStrategy.INHERITED_ANNOTATIONS, RepeatableContainers.none());
}
private static MergedAnnotations getRepeatableAnnotations(AnnotatedElement element,
@Nullable Class<? extends Annotation> containerType, Class<? extends Annotation> annotationType) {
RepeatableContainers repeatableContainers = RepeatableContainers.of(annotationType, containerType);
return MergedAnnotations.from(element, SearchStrategy.INHERITED_ANNOTATIONS, repeatableContainers);
}
private static MergedAnnotations findAnnotations(AnnotatedElement element) {
return MergedAnnotations.from(element, SearchStrategy.TYPE_HIERARCHY, RepeatableContainers.none());
}
private static MergedAnnotations findRepeatableAnnotations(AnnotatedElement element,
@Nullable Class<? extends Annotation> containerType, Class<? extends Annotation> annotationType) {
RepeatableContainers repeatableContainers = RepeatableContainers.of(annotationType, containerType);
return MergedAnnotations.from(element, SearchStrategy.TYPE_HIERARCHY, repeatableContainers);
}
@Nullable
private static MultiValueMap<String, Object> nullIfEmpty(MultiValueMap<String, Object> map) {
return (map.isEmpty() ? null : map);
}
private static <A extends Annotation> Comparator<MergedAnnotation<A>> highAggregateIndexesFirst() {
return Comparator.<MergedAnnotation<A>> comparingInt(
MergedAnnotation::getAggregateIndex).reversed();
}
@Nullable
private static AnnotationAttributes getAnnotationAttributes(MergedAnnotation<?> annotation,
boolean classValuesAsString, boolean nestedAnnotationsAsMap) {
if (!annotation.isPresent()) {
return null;
}
return annotation.asAnnotationAttributes(
Adapt.values(classValuesAsString, nestedAnnotationsAsMap));
}
Adapted AnnotatedElement
that hold specific annotations. /**
* Adapted {@link AnnotatedElement} that hold specific annotations.
*/
private static class AnnotatedElementForAnnotations implements AnnotatedElement {
private final Annotation[] annotations;
AnnotatedElementForAnnotations(Annotation... annotations) {
this.annotations = annotations;
}
@Override
@SuppressWarnings("unchecked")
@Nullable
public <T extends Annotation> T getAnnotation(Class<T> annotationClass) {
for (Annotation annotation : this.annotations) {
if (annotation.annotationType() == annotationClass) {
return (T) annotation;
}
}
return null;
}
@Override
public Annotation[] getAnnotations() {
return this.annotations.clone();
}
@Override
public Annotation[] getDeclaredAnnotations() {
return this.annotations.clone();
}
}
}