From 477d4c5126ac986083ed2678be84641fca106dbf Mon Sep 17 00:00:00 2001 From: Sam Brannen Date: Thu, 14 May 2015 21:25:24 +0200 Subject: [PATCH] Document "present" terminology in AnnotationUtils Prior to this commit, the documentation in AnnotationUtils was inconsistent, and at times even misleading, with regard to finding annotations that are "present" or "directly present" on annotated elements. This commit defines the terminology used within AnnotationUtils and introduces the explicit notion of "meta-present" to denote that annotations are present within annotation hierarchies above annotated elements. Issue: SPR-13030 --- .../core/annotation/AnnotationUtils.java | 177 ++++++++++-------- 1 file changed, 95 insertions(+), 82 deletions(-) diff --git a/spring-core/src/main/java/org/springframework/core/annotation/AnnotationUtils.java b/spring-core/src/main/java/org/springframework/core/annotation/AnnotationUtils.java index b7e21147c9..22b6f13c8b 100644 --- a/spring-core/src/main/java/org/springframework/core/annotation/AnnotationUtils.java +++ b/spring-core/src/main/java/org/springframework/core/annotation/AnnotationUtils.java @@ -54,12 +54,20 @@ import org.springframework.util.StringUtils; * ({@link #getAnnotation(Method, Class)}) and a find lookup in the entire * inheritance hierarchy of the given method ({@link #findAnnotation(Method, Class)}). * + *

Terminology

+ * The terms directly present and present have the same + * meanings as defined in the class-level Javadoc for {@link AnnotatedElement}. + * + *

An annotation is meta-present on an element if the annotation + * is declared as a meta-annotation on some other annotation which is + * present on the element. + * *

Meta-annotation Support

- *

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 - * attribute overrides in composed annotations, use - * {@link AnnotatedElementUtils} instead. + *

Most {@code find*()} methods and some {@code get*()} methods in this + * class provide support for finding annotations used as meta-annotations. + * Consult the Javadoc for each method in this class for details. For support + * for meta-annotations with attribute overrides in + * composed annotations, use {@link AnnotatedElementUtils} instead. * *

Search Scope

*

The search algorithms used by methods in this class stop searching for @@ -122,8 +130,8 @@ public abstract class AnnotationUtils { /** * Get a single {@link Annotation} of {@code annotationType} from the supplied - * {@link AnnotatedElement}, where the {@code AnnotatedElement} is either - * directly annotated or meta-annotated with the {@code annotationType}. + * {@link AnnotatedElement}, where the annotation is either present or + * meta-present on the {@code AnnotatedElement}. *

Note that this method supports only a single level of meta-annotations. * For support for arbitrary levels of meta-annotations, use * {@link #findAnnotation(AnnotatedElement, Class)} instead. @@ -154,8 +162,8 @@ public abstract class AnnotationUtils { /** * Get a single {@link Annotation} of {@code annotationType} from the - * supplied {@link Method}, where the method is either directly annotated - * or meta-annotated with the {@code annotationType}. + * supplied {@link Method}, where the annotation is either present + * or meta-present on the method. *

Correctly handles bridge {@link Method Methods} generated by the compiler. *

Note that this method supports only a single level of meta-annotations. * For support for arbitrary levels of meta-annotations, use @@ -216,15 +224,17 @@ public abstract class AnnotationUtils { } /** - * 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 repeatable {@link Annotation}s of {@code annotationType} + * from the supplied {@link Method}, where such annotations are either + * present or meta-present on the method. + *

Handles both single annotations and annotations nested within a + * containing annotation. *

Correctly handles bridge {@link Method Methods} generated by the compiler. *

Meta-annotations will be searched if the annotation is not - * directly present on the supplied method. - * @param method the method to look for annotations on - * @param containerAnnotationType the class of the container that holds the annotations + * present on the supplied method. + * @param method the method to look for annotations on; never {@code null} + * @param containerAnnotationType the type of the container that holds the + * annotations; may be {@code null} if a container is not supported * @param annotationType the annotation type to look for * @return the annotations found or an empty set; never {@code null} * @since 4.0 @@ -239,14 +249,16 @@ 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. + * Get the repeatable {@link Annotation}s of {@code annotationType} + * from the supplied {@link AnnotatedElement}, where such annotations are + * either present or meta-present on the element. + *

Handles both single annotations and annotations nested within a + * containing annotation. *

Meta-annotations will be searched if the annotation is not - * directly present on the supplied element. - * @param annotatedElement the element to look for annotations on - * @param containerAnnotationType the class of the container that holds the annotations + * present on the supplied element. + * @param annotatedElement the element to look for annotations on; never {@code null} + * @param containerAnnotationType the type of the container that holds the + * annotations; may be {@code null} if a container is not supported * @param annotationType the annotation type to look for * @return the annotations found or an empty set; never {@code null} * @since 4.0 @@ -328,7 +340,8 @@ public abstract class AnnotationUtils { /** * Find a single {@link Annotation} of {@code annotationType} on the supplied * {@link Method}, traversing its super methods (i.e., from superclasses and - * interfaces) if no annotation can be found on the given method itself. + * interfaces) if the annotation is not directly present on the given + * method itself. *

Correctly handles bridge {@link Method Methods} generated by the compiler. *

Meta-annotations will be searched if the annotation is not * directly present on the method. @@ -423,8 +436,8 @@ public abstract class AnnotationUtils { /** * Find a single {@link Annotation} of {@code annotationType} on the * supplied {@link Class}, traversing its interfaces, annotations, and - * superclasses if the annotation is not present on the given class - * itself. + * superclasses if the annotation is not directly present on + * the given class itself. *

This method explicitly handles class-level annotations which are not * declared as {@link java.lang.annotation.Inherited inherited} as well * as meta-annotations and annotations on interfaces. @@ -505,21 +518,22 @@ public abstract class AnnotationUtils { } /** - * Find the first {@link Class} in the inheritance hierarchy of the specified {@code clazz} - * (including the specified {@code clazz} itself) which declares an annotation for the - * specified {@code annotationType}, or {@code null} if not found. If the supplied - * {@code clazz} is {@code null}, {@code null} will be returned. - *

If the supplied {@code clazz} is an interface, only the interface itself will be checked; - * the inheritance hierarchy for interfaces will not be traversed. + * Find the first {@link Class} in the inheritance hierarchy of the + * specified {@code clazz} (including the specified {@code clazz} itself) + * on which an annotation of the specified {@code annotationType} is + * directly present. + *

If the supplied {@code clazz} is an interface, only the interface + * itself will be checked; the inheritance hierarchy for interfaces will + * not be traversed. *

Meta-annotations will not be searched. - *

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 of the specified {@code annotationType}, or {@code null} - * if not found + *

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 + * @param clazz the class to check for the annotation on (may be {@code null}) + * @return the first {@link Class} in the inheritance hierarchy that + * declares an annotation of the specified {@code annotationType}, or + * {@code null} if not found * @see Class#isAnnotationPresent(Class) * @see Class#getDeclaredAnnotations() * @see #findAnnotationDeclaringClassForTypes(List, Class) @@ -537,25 +551,22 @@ public abstract class AnnotationUtils { } /** - * Find the first {@link Class} in the inheritance hierarchy of the specified - * {@code clazz} (including the specified {@code clazz} itself) which declares - * at least one of the specified {@code annotationTypes}, or {@code null} if - * none of the specified annotation types could be found. - *

If the supplied {@code clazz} is {@code null}, {@code null} will be - * returned. - *

If the supplied {@code clazz} is an interface, only the interface itself - * will be checked; the inheritance hierarchy for interfaces will not be traversed. + * Find the first {@link Class} in the inheritance hierarchy of the + * specified {@code clazz} (including the specified {@code clazz} itself) + * on which at least one of the specified {@code annotationTypes} is + * directly present. + *

If the supplied {@code clazz} is an interface, only the interface + * itself will be checked; the inheritance hierarchy for interfaces will + * not be traversed. *

Meta-annotations will not be searched. - *

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 - * explicitly. - * @param annotationTypes the list of Class objects corresponding to the - * annotation types - * @param clazz the Class object corresponding to the class on which to check - * for the annotations, or {@code null} - * @return the first {@link Class} in the inheritance hierarchy of the specified - * {@code clazz} which declares an annotation of at least one of the specified + *

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 explicitly. + * @param annotationTypes the annotation types to look for + * @param clazz the class to check for the annotations on, or {@code null} + * @return the first {@link Class} in the inheritance hierarchy that + * declares an annotation of at least one of the specified * {@code annotationTypes}, or {@code null} if not found * @since 3.2.2 * @see Class#isAnnotationPresent(Class) @@ -577,18 +588,19 @@ public abstract class AnnotationUtils { } /** - * Determine whether an annotation of the specified {@code annotationType} is - * declared locally (i.e., directly present) 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., directly present) on the supplied + * {@code clazz}. + *

The supplied {@link Class} may represent any type. *

Meta-annotations will not be searched. - *

Note: This method does not determine if the annotation is - * {@linkplain java.lang.annotation.Inherited inherited}. For greater clarity - * regarding inherited annotations, consider using + *

Note: This method does not 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 + * @param annotationType the annotation type to look for + * @param clazz the class to check for the annotation on * @return {@code true} if an annotation of the specified {@code annotationType} - * is directly present on the supplied {@code clazz} + * is directly present * @see java.lang.Class#getDeclaredAnnotations() * @see java.lang.Class#getDeclaredAnnotation(Class) * @see #isAnnotationInherited(Class, Class) @@ -596,12 +608,10 @@ public abstract class AnnotationUtils { public static boolean isAnnotationDeclaredLocally(Class annotationType, Class clazz) { Assert.notNull(annotationType, "Annotation type must not be null"); Assert.notNull(clazz, "Class must not be null"); - boolean declaredLocally = false; try { for (Annotation ann : clazz.getDeclaredAnnotations()) { if (ann.annotationType().equals(annotationType)) { - declaredLocally = true; - break; + return true; } } } @@ -609,22 +619,25 @@ public abstract class AnnotationUtils { // Assuming nested Class values not resolvable within annotation attributes... logIntrospectionFailure(clazz, ex); } - return declaredLocally; + return false; } /** - * Determine whether an annotation of the specified {@code annotationType} is present - * on the supplied {@code clazz} and is {@linkplain java.lang.annotation.Inherited inherited} - * (i.e., not declared locally for the class). + * Determine whether an annotation of the specified {@code annotationType} + * is present on the supplied {@code clazz} and is + * {@linkplain java.lang.annotation.Inherited inherited} (i.e., not + * directly present). *

Meta-annotations will not be searched. - *

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 of the specified {@code annotationType} is present - * on the supplied {@code clazz} and is inherited + *

If the supplied {@code clazz} is an interface, only the interface + * itself will be checked. In accordance with standard meta-annotation + * semantics in Java, the inheritance hierarchy for interfaces will not + * be traversed. See the {@linkplain java.lang.annotation.Inherited Javadoc} + * for the {@code @Inherited} meta-annotation for further details regarding + * annotation inheritance. + * @param annotationType the annotation type to look for + * @param clazz the class to check for the annotation on + * @return {@code true} if an annotation of the specified {@code annotationType} + * is present and inherited * @see Class#isAnnotationPresent(Class) * @see #isAnnotationDeclaredLocally(Class, Class) */