|
|
|
@ -38,10 +38,12 @@ import org.springframework.util.ReflectionUtils; |
|
|
|
|
import org.springframework.util.StringUtils; |
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
* General utility methods for working with annotations, handling bridge methods |
|
|
|
|
* (which the compiler generates for generic declarations) as well as super methods |
|
|
|
|
* (for optional "annotation inheritance"). Note that none of this is |
|
|
|
|
* provided by the JDK's introspection facilities themselves. |
|
|
|
|
* General utility methods for working with annotations, handling meta-annotations, |
|
|
|
|
* bridge methods (which the compiler generates for generic declarations) as well |
|
|
|
|
* as super methods (for optional <em>annotation inheritance</em>). |
|
|
|
|
* |
|
|
|
|
* <p>Note that most of the features of this class are not provided by the |
|
|
|
|
* JDK's introspection facilities themselves. |
|
|
|
|
* |
|
|
|
|
* <p>As a general rule for runtime-retained annotations (e.g. for transaction |
|
|
|
|
* control, authorization, or service exposure), always use the lookup methods |
|
|
|
@ -52,6 +54,13 @@ import org.springframework.util.StringUtils; |
|
|
|
|
* ({@link #getAnnotation(Method, Class)}) and a <em>find</em> lookup in the entire |
|
|
|
|
* inheritance hierarchy of the given method ({@link #findAnnotation(Method, Class)}). |
|
|
|
|
* |
|
|
|
|
* <h3>Meta-annotation Support</h3> |
|
|
|
|
* <p>Most {@code find*()} methods and some {@code get*()} methods in this class
|
|
|
|
|
* provide support for meta-annotations. Consult the Javadoc for each method in |
|
|
|
|
* this class for details. For support for meta-annotations with |
|
|
|
|
* <em>attribute overrides</em> in <em>composed annotations</em>, use |
|
|
|
|
* {@link AnnotatedElementUtils} instead. |
|
|
|
|
* |
|
|
|
|
* @author Rob Harrop |
|
|
|
|
* @author Juergen Hoeller |
|
|
|
|
* @author Sam Brannen |
|
|
|
@ -59,8 +68,9 @@ import org.springframework.util.StringUtils; |
|
|
|
|
* @author Chris Beams |
|
|
|
|
* @author Phillip Webb |
|
|
|
|
* @since 2.0 |
|
|
|
|
* @see java.lang.reflect.Method#getAnnotations() |
|
|
|
|
* @see java.lang.reflect.Method#getAnnotation(Class) |
|
|
|
|
* @see java.lang.reflect.AnnotatedElement#getAnnotations() |
|
|
|
|
* @see java.lang.reflect.AnnotatedElement#getAnnotation(Class) |
|
|
|
|
* @see java.lang.reflect.AnnotatedElement#getDeclaredAnnotations() |
|
|
|
|
*/ |
|
|
|
|
public abstract class AnnotationUtils { |
|
|
|
|
|
|
|
|
@ -79,10 +89,13 @@ public abstract class AnnotationUtils { |
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
* Get a single {@link Annotation} of {@code annotationType} from the supplied |
|
|
|
|
* annotation: either the given annotation itself or a meta-annotation thereof. |
|
|
|
|
* annotation: either the given annotation itself or a direct meta-annotation |
|
|
|
|
* thereof. |
|
|
|
|
* <p>Note that this method does <em>not</em> support arbitrary levels of |
|
|
|
|
* meta-annotations. |
|
|
|
|
* @param ann the Annotation to check |
|
|
|
|
* @param annotationType the annotation type to look for, both locally and as a meta-annotation |
|
|
|
|
* @return the matching annotation, or {@code null} if none found |
|
|
|
|
* @return the matching annotation, or {@code null} if not found |
|
|
|
|
* @since 4.0 |
|
|
|
|
*/ |
|
|
|
|
@SuppressWarnings("unchecked") |
|
|
|
@ -102,11 +115,12 @@ public abstract class AnnotationUtils { |
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
* Get a single {@link Annotation} of {@code annotationType} from the supplied |
|
|
|
|
* Method, Constructor or Field. Meta-annotations will be searched if the annotation |
|
|
|
|
* is not declared locally on the supplied element. |
|
|
|
|
* @param annotatedElement the Method, Constructor or Field from which to get the annotation |
|
|
|
|
* {@link AnnotatedElement}. |
|
|
|
|
* <p>Meta-annotations will be searched if the annotation is not |
|
|
|
|
* <em>directly present</em> on the supplied element. |
|
|
|
|
* @param annotatedElement the {@code AnnotatedElement} from which to get the annotation |
|
|
|
|
* @param annotationType the annotation type to look for, both locally and as a meta-annotation |
|
|
|
|
* @return the matching annotation, or {@code null} if none found |
|
|
|
|
* @return the matching annotation, or {@code null} if not found |
|
|
|
|
* @since 3.1 |
|
|
|
|
*/ |
|
|
|
|
public static <T extends Annotation> T getAnnotation(AnnotatedElement annotatedElement, Class<T> annotationType) { |
|
|
|
@ -130,10 +144,29 @@ public abstract class AnnotationUtils { |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
* Get all {@link Annotation Annotations} from the supplied Method, Constructor or Field. |
|
|
|
|
* Get a single {@link Annotation} of {@code annotationType} from the supplied {@link Method}. |
|
|
|
|
* <p>Correctly handles bridge {@link Method Methods} generated by the compiler. |
|
|
|
|
* <p>Meta-annotations will be searched if the annotation is not |
|
|
|
|
* <em>directly present</em> on the supplied method. |
|
|
|
|
* @param method the method to look for annotations on |
|
|
|
|
* @param annotationType the annotation type to look for |
|
|
|
|
* @return the matching annotation, or {@code null} if not found |
|
|
|
|
* @see org.springframework.core.BridgeMethodResolver#findBridgedMethod(Method) |
|
|
|
|
* @see #getAnnotation(AnnotatedElement, Class) |
|
|
|
|
*/ |
|
|
|
|
public static <A extends Annotation> A getAnnotation(Method method, Class<A> annotationType) { |
|
|
|
|
Method resolvedMethod = BridgeMethodResolver.findBridgedMethod(method); |
|
|
|
|
return getAnnotation((AnnotatedElement) resolvedMethod, annotationType); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
* Get all {@link Annotation Annotations} that are <em>present</em> on the |
|
|
|
|
* supplied {@link AnnotatedElement}. |
|
|
|
|
* <p>Meta-annotations will <em>not</em> be searched. |
|
|
|
|
* @param annotatedElement the Method, Constructor or Field to retrieve annotations from |
|
|
|
|
* @return the annotations found, or {@code null} if not resolvable (e.g. because nested |
|
|
|
|
* Class values in annotation attributes failed to resolve at runtime) |
|
|
|
|
* @return the annotations found, an empty array, or {@code null} if not |
|
|
|
|
* resolvable (e.g. because nested Class values in annotation attributes |
|
|
|
|
* failed to resolve at runtime) |
|
|
|
|
* @since 4.0.8 |
|
|
|
|
*/ |
|
|
|
|
public static Annotation[] getAnnotations(AnnotatedElement annotatedElement) { |
|
|
|
@ -143,16 +176,21 @@ public abstract class AnnotationUtils { |
|
|
|
|
catch (Exception ex) { |
|
|
|
|
// Assuming nested Class values not resolvable within annotation attributes...
|
|
|
|
|
logIntrospectionFailure(annotatedElement, ex); |
|
|
|
|
return null; |
|
|
|
|
} |
|
|
|
|
return null; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
* Get all {@link Annotation Annotations} from the supplied {@link Method}. |
|
|
|
|
* Get all {@link Annotation Annotations} that are <em>present</em on the |
|
|
|
|
* supplied {@link Method}. |
|
|
|
|
* <p>Correctly handles bridge {@link Method Methods} generated by the compiler. |
|
|
|
|
* <p>Meta-annotations will <em>not</em> be searched. |
|
|
|
|
* @param method the Method to retrieve annotations from |
|
|
|
|
* @return the annotations found |
|
|
|
|
* @return the annotations found, an empty array, or {@code null} if not |
|
|
|
|
* resolvable (e.g. because nested Class values in annotation attributes |
|
|
|
|
* failed to resolve at runtime) |
|
|
|
|
* @see org.springframework.core.BridgeMethodResolver#findBridgedMethod(Method) |
|
|
|
|
* @see AnnotatedElement#getAnnotations() |
|
|
|
|
*/ |
|
|
|
|
public static Annotation[] getAnnotations(Method method) { |
|
|
|
|
try { |
|
|
|
@ -161,34 +199,25 @@ public abstract class AnnotationUtils { |
|
|
|
|
catch (Exception ex) { |
|
|
|
|
// Assuming nested Class values not resolvable within annotation attributes...
|
|
|
|
|
logIntrospectionFailure(method, ex); |
|
|
|
|
return null; |
|
|
|
|
} |
|
|
|
|
return null; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
* Get a single {@link Annotation} of {@code annotationType} from the supplied {@link Method}. |
|
|
|
|
* <p>Correctly handles bridge {@link Method Methods} generated by the compiler. |
|
|
|
|
* @param method the method to look for annotations on |
|
|
|
|
* @param annotationType the annotation type to look for |
|
|
|
|
* @return the annotations found |
|
|
|
|
* @see org.springframework.core.BridgeMethodResolver#findBridgedMethod(Method) |
|
|
|
|
*/ |
|
|
|
|
public static <A extends Annotation> A getAnnotation(Method method, Class<A> annotationType) { |
|
|
|
|
Method resolvedMethod = BridgeMethodResolver.findBridgedMethod(method); |
|
|
|
|
return getAnnotation((AnnotatedElement) resolvedMethod, annotationType); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
* Get the possibly repeating {@link Annotation}s of {@code annotationType} from the |
|
|
|
|
* supplied {@link Method}. Deals with both a single direct annotation and repeating |
|
|
|
|
* annotations nested within a containing annotation. |
|
|
|
|
* Get the possibly repeating {@link Annotation}s of {@code annotationType} |
|
|
|
|
* from the supplied {@link Method}. |
|
|
|
|
* <p>Deals with both a single direct annotation and repeating annotations |
|
|
|
|
* nested within a containing annotation. |
|
|
|
|
* <p>Correctly handles bridge {@link Method Methods} generated by the compiler. |
|
|
|
|
* <p>Meta-annotations will be searched if the annotation is not |
|
|
|
|
* <em>directly present</em> on the supplied method. |
|
|
|
|
* @param method the method to look for annotations on |
|
|
|
|
* @param containerAnnotationType the class of the container that holds the annotations |
|
|
|
|
* @param annotationType the annotation type to look for |
|
|
|
|
* @return the annotations found |
|
|
|
|
* @return the annotations found or an empty set; never {@code null} |
|
|
|
|
* @since 4.0 |
|
|
|
|
* @see org.springframework.core.BridgeMethodResolver#findBridgedMethod(Method) |
|
|
|
|
* @see java.lang.annotation.Repeatable |
|
|
|
|
*/ |
|
|
|
|
public static <A extends Annotation> Set<A> getRepeatableAnnotation(Method method, |
|
|
|
|
Class<? extends Annotation> containerAnnotationType, Class<A> annotationType) { |
|
|
|
@ -199,15 +228,17 @@ public abstract class AnnotationUtils { |
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
* Get the possibly repeating {@link Annotation}s of {@code annotationType} from the |
|
|
|
|
* supplied {@link AnnotatedElement}. Deals with both a single direct annotation and |
|
|
|
|
* repeating annotations nested within a containing annotation. |
|
|
|
|
* <p>Correctly handles bridge {@link Method Methods} generated by the compiler. |
|
|
|
|
* supplied {@link AnnotatedElement}. |
|
|
|
|
* <p>Deals with both a single direct annotation and repeating annotations |
|
|
|
|
* nested within a containing annotation. |
|
|
|
|
* <p>Meta-annotations will be searched if the annotation is not |
|
|
|
|
* <em>directly present</em> on the supplied element. |
|
|
|
|
* @param annotatedElement the element to look for annotations on |
|
|
|
|
* @param containerAnnotationType the class of the container that holds the annotations |
|
|
|
|
* @param annotationType the annotation type to look for |
|
|
|
|
* @return the annotations found |
|
|
|
|
* @return the annotations found or an empty set; never {@code null} |
|
|
|
|
* @since 4.0 |
|
|
|
|
* @see org.springframework.core.BridgeMethodResolver#findBridgedMethod(Method) |
|
|
|
|
* @see java.lang.annotation.Repeatable |
|
|
|
|
*/ |
|
|
|
|
public static <A extends Annotation> Set<A> getRepeatableAnnotation(AnnotatedElement annotatedElement, |
|
|
|
|
Class<? extends Annotation> containerAnnotationType, Class<A> annotationType) { |
|
|
|
@ -230,9 +261,10 @@ public abstract class AnnotationUtils { |
|
|
|
|
* interfaces) if no annotation can be found on the given method itself. |
|
|
|
|
* <p>Annotations on methods are not inherited by default, so we need to handle |
|
|
|
|
* this explicitly. |
|
|
|
|
* <p>Meta-annotations will <em>not</em> be searched. |
|
|
|
|
* @param method the method to look for annotations on |
|
|
|
|
* @param annotationType the annotation type to look for |
|
|
|
|
* @return the annotation found, or {@code null} if none |
|
|
|
|
* @return the matching annotation, or {@code null} if not found |
|
|
|
|
*/ |
|
|
|
|
@SuppressWarnings("unchecked") |
|
|
|
|
public static <A extends Annotation> A findAnnotation(Method method, Class<A> annotationType) { |
|
|
|
@ -328,7 +360,7 @@ public abstract class AnnotationUtils { |
|
|
|
|
* annotation, or superclass as the class to look for annotations on. |
|
|
|
|
* @param clazz the class to look for annotations on |
|
|
|
|
* @param annotationType the type of annotation to look for |
|
|
|
|
* @return the annotation if found, or {@code null} if not found |
|
|
|
|
* @return the matching annotation, or {@code null} if not found |
|
|
|
|
*/ |
|
|
|
|
@SuppressWarnings("unchecked") |
|
|
|
|
public static <A extends Annotation> A findAnnotation(Class<?> clazz, Class<A> annotationType) { |
|
|
|
@ -350,7 +382,7 @@ public abstract class AnnotationUtils { |
|
|
|
|
* @param clazz the class to look for annotations on |
|
|
|
|
* @param annotationType the type of annotation to look for |
|
|
|
|
* @param visited the set of annotations that have already been visited |
|
|
|
|
* @return the annotation if found, or {@code null} if not found |
|
|
|
|
* @return the matching annotation, or {@code null} if not found |
|
|
|
|
*/ |
|
|
|
|
@SuppressWarnings("unchecked") |
|
|
|
|
private static <A extends Annotation> A findAnnotation(Class<?> clazz, Class<A> annotationType, Set<Annotation> visited) { |
|
|
|
@ -399,13 +431,14 @@ public abstract class AnnotationUtils { |
|
|
|
|
* {@code clazz} is {@code null}, {@code null} will be returned. |
|
|
|
|
* <p>If the supplied {@code clazz} is an interface, only the interface itself will be checked; |
|
|
|
|
* the inheritance hierarchy for interfaces will not be traversed. |
|
|
|
|
* <p>Meta-annotations will <em>not</em> be searched. |
|
|
|
|
* <p>The standard {@link Class} API does not provide a mechanism for determining which class
|
|
|
|
|
* in an inheritance hierarchy actually declares an {@link Annotation}, so we need to handle |
|
|
|
|
* this explicitly. |
|
|
|
|
* @param annotationType the annotation type to look for, both locally and as a meta-annotation |
|
|
|
|
* @param clazz the class on which to check for the annotation (may be {@code null}) |
|
|
|
|
* @return the first {@link Class} in the inheritance hierarchy of the specified {@code clazz} |
|
|
|
|
* which declares an annotation for the specified {@code annotationType}, or {@code null} |
|
|
|
|
* which declares an annotation of the specified {@code annotationType}, or {@code null} |
|
|
|
|
* if not found |
|
|
|
|
* @see Class#isAnnotationPresent(Class) |
|
|
|
|
* @see Class#getDeclaredAnnotations() |
|
|
|
@ -432,6 +465,7 @@ public abstract class AnnotationUtils { |
|
|
|
|
* returned. |
|
|
|
|
* <p>If the supplied {@code clazz} is an interface, only the interface itself |
|
|
|
|
* will be checked; the inheritance hierarchy for interfaces will not be traversed. |
|
|
|
|
* <p>Meta-annotations will <em>not</em> be searched. |
|
|
|
|
* <p>The standard {@link Class} API does not provide a mechanism for determining |
|
|
|
|
* which class in an inheritance hierarchy actually declares one of several |
|
|
|
|
* candidate {@linkplain Annotation annotations}, so we need to handle this |
|
|
|
@ -463,18 +497,20 @@ public abstract class AnnotationUtils { |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
* Determine whether an annotation for the specified {@code annotationType} is |
|
|
|
|
* declared locally on the supplied {@code clazz}. The supplied {@link Class} |
|
|
|
|
* may represent any type. |
|
|
|
|
* Determine whether an annotation of the specified {@code annotationType} is |
|
|
|
|
* declared locally (i.e., <em>directly present</em>) on the supplied |
|
|
|
|
* {@code clazz}. The supplied {@link Class} may represent any type. |
|
|
|
|
* <p>Meta-annotations will <em>not</em> be searched. |
|
|
|
|
* <p>Note: This method does <strong>not</strong> determine if the annotation is |
|
|
|
|
* {@linkplain java.lang.annotation.Inherited inherited}. For greater clarity |
|
|
|
|
* regarding inherited annotations, consider using |
|
|
|
|
* {@link #isAnnotationInherited(Class, Class)} instead. |
|
|
|
|
* @param annotationType the Class object corresponding to the annotation type |
|
|
|
|
* @param clazz the Class object corresponding to the class on which to check for the annotation |
|
|
|
|
* @return {@code true} if an annotation for the specified {@code annotationType} |
|
|
|
|
* is declared locally on the supplied {@code clazz} |
|
|
|
|
* @see Class#getDeclaredAnnotations() |
|
|
|
|
* @return {@code true} if an annotation of the specified {@code annotationType} |
|
|
|
|
* is <em>directly present</em> on the supplied {@code clazz} |
|
|
|
|
* @see java.lang.Class#getDeclaredAnnotations() |
|
|
|
|
* @see java.lang.Class#getDeclaredAnnotation(Class) |
|
|
|
|
* @see #isAnnotationInherited(Class, Class) |
|
|
|
|
*/ |
|
|
|
|
public static boolean isAnnotationDeclaredLocally(Class<? extends Annotation> annotationType, Class<?> clazz) { |
|
|
|
@ -497,16 +533,17 @@ public abstract class AnnotationUtils { |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
* Determine whether an annotation for the specified {@code annotationType} is present |
|
|
|
|
* Determine whether an annotation of the specified {@code annotationType} is <em>present</em> |
|
|
|
|
* on the supplied {@code clazz} and is {@linkplain java.lang.annotation.Inherited inherited} |
|
|
|
|
* (i.e., not declared locally for the class). |
|
|
|
|
* <p>Meta-annotations will <em>not</em> be searched. |
|
|
|
|
* <p>If the supplied {@code clazz} is an interface, only the interface itself will be checked. |
|
|
|
|
* In accordance with standard meta-annotation semantics, the inheritance hierarchy for interfaces |
|
|
|
|
* will not be traversed. See the {@linkplain java.lang.annotation.Inherited Javadoc} for the |
|
|
|
|
* {@code @Inherited} meta-annotation for further details regarding annotation inheritance. |
|
|
|
|
* @param annotationType the Class object corresponding to the annotation type |
|
|
|
|
* @param clazz the Class object corresponding to the class on which to check for the annotation |
|
|
|
|
* @return {@code true} if an annotation for the specified {@code annotationType} is present |
|
|
|
|
* @return {@code true} if an annotation of the specified {@code annotationType} is present |
|
|
|
|
* on the supplied {@code clazz} and is <em>inherited</em> |
|
|
|
|
* @see Class#isAnnotationPresent(Class) |
|
|
|
|
* @see #isAnnotationDeclaredLocally(Class, Class) |
|
|
|
@ -530,21 +567,25 @@ public abstract class AnnotationUtils { |
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
* Retrieve the given annotation's attributes as a {@link Map}, preserving all |
|
|
|
|
* attribute types as-is. |
|
|
|
|
* attribute types. |
|
|
|
|
* <p>Equivalent to calling {@link #getAnnotationAttributes(Annotation, boolean, boolean)} |
|
|
|
|
* with the {@code classValuesAsString} and {@code nestedAnnotationsAsMap} parameters |
|
|
|
|
* set to {@code false}. |
|
|
|
|
* <p>Note: This method actually returns an {@link AnnotationAttributes} instance. |
|
|
|
|
* However, the {@code Map} signature has been preserved for binary compatibility. |
|
|
|
|
* @param annotation the annotation to retrieve the attributes for |
|
|
|
|
* @return the Map of annotation attributes, with attribute names as keys and |
|
|
|
|
* corresponding attribute values as values |
|
|
|
|
* corresponding attribute values as values; never {@code null} |
|
|
|
|
* @see #getAnnotationAttributes(Annotation, boolean, boolean) |
|
|
|
|
*/ |
|
|
|
|
public static Map<String, Object> getAnnotationAttributes(Annotation annotation) { |
|
|
|
|
return getAnnotationAttributes(annotation, false, false); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
* Retrieve the given annotation's attributes as a {@link Map}. Equivalent to |
|
|
|
|
* calling {@link #getAnnotationAttributes(Annotation, boolean, boolean)} with |
|
|
|
|
* the {@code nestedAnnotationsAsMap} parameter set to {@code false}. |
|
|
|
|
* Retrieve the given annotation's attributes as a {@link Map}. |
|
|
|
|
* <p>Equivalent to calling {@link #getAnnotationAttributes(Annotation, boolean, boolean)} |
|
|
|
|
* with the {@code nestedAnnotationsAsMap} parameter set to {@code false}. |
|
|
|
|
* <p>Note: This method actually returns an {@link AnnotationAttributes} instance. |
|
|
|
|
* However, the {@code Map} signature has been preserved for binary compatibility. |
|
|
|
|
* @param annotation the annotation to retrieve the attributes for |
|
|
|
@ -552,7 +593,8 @@ public abstract class AnnotationUtils { |
|
|
|
|
* compatibility with {@link org.springframework.core.type.AnnotationMetadata} |
|
|
|
|
* or to preserve them as Class references |
|
|
|
|
* @return the Map of annotation attributes, with attribute names as keys and |
|
|
|
|
* corresponding attribute values as values |
|
|
|
|
* corresponding attribute values as values; never {@code null} |
|
|
|
|
* @see #getAnnotationAttributes(Annotation, boolean, boolean) |
|
|
|
|
*/ |
|
|
|
|
public static Map<String, Object> getAnnotationAttributes(Annotation annotation, boolean classValuesAsString) { |
|
|
|
|
return getAnnotationAttributes(annotation, classValuesAsString, false); |
|
|
|
@ -564,7 +606,7 @@ public abstract class AnnotationUtils { |
|
|
|
|
* <p>This method provides fully recursive annotation reading capabilities on par with |
|
|
|
|
* the reflection-based {@link org.springframework.core.type.StandardAnnotationMetadata}. |
|
|
|
|
* @param annotation the annotation to retrieve the attributes for |
|
|
|
|
* @param classValuesAsString whether to turn Class references into Strings (for |
|
|
|
|
* @param classValuesAsString whether to convert Class references into Strings (for |
|
|
|
|
* compatibility with {@link org.springframework.core.type.AnnotationMetadata} |
|
|
|
|
* or to preserve them as Class references |
|
|
|
|
* @param nestedAnnotationsAsMap whether to turn nested Annotation instances into |
|
|
|
@ -572,7 +614,7 @@ public abstract class AnnotationUtils { |
|
|
|
|
* {@link org.springframework.core.type.AnnotationMetadata} or to preserve them as |
|
|
|
|
* Annotation instances |
|
|
|
|
* @return the annotation attributes (a specialized Map) with attribute names as keys |
|
|
|
|
* and corresponding attribute values as values |
|
|
|
|
* and corresponding attribute values as values; never {@code null} |
|
|
|
|
* @since 3.1.1 |
|
|
|
|
*/ |
|
|
|
|
public static AnnotationAttributes getAnnotationAttributes(Annotation annotation, boolean classValuesAsString, |
|
|
|
@ -813,14 +855,15 @@ public abstract class AnnotationUtils { |
|
|
|
|
if (this.visited.add(element)) { |
|
|
|
|
try { |
|
|
|
|
for (Annotation ann : element.getAnnotations()) { |
|
|
|
|
if (ObjectUtils.nullSafeEquals(this.annotationType, ann.annotationType())) { |
|
|
|
|
Class<? extends Annotation> currentAnnotationType = ann.annotationType(); |
|
|
|
|
if (ObjectUtils.nullSafeEquals(this.annotationType, currentAnnotationType)) { |
|
|
|
|
this.result.add((A) ann); |
|
|
|
|
} |
|
|
|
|
else if (ObjectUtils.nullSafeEquals(this.containerAnnotationType, ann.annotationType())) { |
|
|
|
|
else if (ObjectUtils.nullSafeEquals(this.containerAnnotationType, currentAnnotationType)) { |
|
|
|
|
this.result.addAll(getValue(ann)); |
|
|
|
|
} |
|
|
|
|
else if (!isInJavaLangAnnotationPackage(ann)) { |
|
|
|
|
process(ann.annotationType()); |
|
|
|
|
process(currentAnnotationType); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|