Skip to content

Commit 477d4c5

Browse files
committed
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
1 parent ca410fe commit 477d4c5

File tree

1 file changed

+95
-82
lines changed

1 file changed

+95
-82
lines changed

spring-core/src/main/java/org/springframework/core/annotation/AnnotationUtils.java

Lines changed: 95 additions & 82 deletions
Original file line numberDiff line numberDiff line change
@@ -54,12 +54,20 @@
5454
* ({@link #getAnnotation(Method, Class)}) and a <em>find</em> lookup in the entire
5555
* inheritance hierarchy of the given method ({@link #findAnnotation(Method, Class)}).
5656
*
57+
* <h3>Terminology</h3>
58+
* The terms <em>directly present</em> and <em>present</em> have the same
59+
* meanings as defined in the class-level Javadoc for {@link AnnotatedElement}.
60+
*
61+
* <p>An annotation is <em>meta-present</em> on an element if the annotation
62+
* is declared as a meta-annotation on some other annotation which is
63+
* <em>present</em> on the element.
64+
*
5765
* <h3>Meta-annotation Support</h3>
58-
* <p>Most {@code find*()} methods and some {@code get*()} methods in this class
59-
* provide support for meta-annotations. Consult the Javadoc for each method in
60-
* this class for details. For support for meta-annotations with
61-
* <em>attribute overrides</em> in <em>composed annotations</em>, use
62-
* {@link AnnotatedElementUtils} instead.
66+
* <p>Most {@code find*()} methods and some {@code get*()} methods in this
67+
* class provide support for finding annotations used as meta-annotations.
68+
* Consult the Javadoc for each method in this class for details. For support
69+
* for meta-annotations with <em>attribute overrides</em> in
70+
* <em>composed annotations</em>, use {@link AnnotatedElementUtils} instead.
6371
*
6472
* <h3>Search Scope</h3>
6573
* <p>The search algorithms used by methods in this class stop searching for
@@ -122,8 +130,8 @@ public static <A extends Annotation> A getAnnotation(Annotation ann, Class<A> an
122130

123131
/**
124132
* Get a single {@link Annotation} of {@code annotationType} from the supplied
125-
* {@link AnnotatedElement}, where the {@code AnnotatedElement} is either
126-
* directly annotated or meta-annotated with the {@code annotationType}.
133+
* {@link AnnotatedElement}, where the annotation is either <em>present</em> or
134+
* <em>meta-present</em> on the {@code AnnotatedElement}.
127135
* <p>Note that this method supports only a single level of meta-annotations.
128136
* For support for arbitrary levels of meta-annotations, use
129137
* {@link #findAnnotation(AnnotatedElement, Class)} instead.
@@ -154,8 +162,8 @@ public static <A extends Annotation> A getAnnotation(AnnotatedElement annotatedE
154162

155163
/**
156164
* Get a single {@link Annotation} of {@code annotationType} from the
157-
* supplied {@link Method}, where the method is either directly annotated
158-
* or meta-annotated with the {@code annotationType}.
165+
* supplied {@link Method}, where the annotation is either <em>present</em>
166+
* or <em>meta-present</em> on the method.
159167
* <p>Correctly handles bridge {@link Method Methods} generated by the compiler.
160168
* <p>Note that this method supports only a single level of meta-annotations.
161169
* For support for arbitrary levels of meta-annotations, use
@@ -216,15 +224,17 @@ public static Annotation[] getAnnotations(Method method) {
216224
}
217225

218226
/**
219-
* Get the possibly repeating {@link Annotation}s of {@code annotationType}
220-
* from the supplied {@link Method}.
221-
* <p>Deals with both a single direct annotation and repeating annotations
222-
* nested within a containing annotation.
227+
* Get the <em>repeatable</em> {@link Annotation}s of {@code annotationType}
228+
* from the supplied {@link Method}, where such annotations are either
229+
* <em>present</em> or <em>meta-present</em> on the method.
230+
* <p>Handles both single annotations and annotations nested within a
231+
* <em>containing annotation</em>.
223232
* <p>Correctly handles bridge {@link Method Methods} generated by the compiler.
224233
* <p>Meta-annotations will be searched if the annotation is not
225-
* <em>directly present</em> on the supplied method.
226-
* @param method the method to look for annotations on
227-
* @param containerAnnotationType the class of the container that holds the annotations
234+
* <em>present</em> on the supplied method.
235+
* @param method the method to look for annotations on; never {@code null}
236+
* @param containerAnnotationType the type of the container that holds the
237+
* annotations; may be {@code null} if a container is not supported
228238
* @param annotationType the annotation type to look for
229239
* @return the annotations found or an empty set; never {@code null}
230240
* @since 4.0
@@ -239,14 +249,16 @@ public static <A extends Annotation> Set<A> getRepeatableAnnotation(Method metho
239249
}
240250

241251
/**
242-
* Get the possibly repeating {@link Annotation}s of {@code annotationType} from the
243-
* supplied {@link AnnotatedElement}.
244-
* <p>Deals with both a single direct annotation and repeating annotations
245-
* nested within a containing annotation.
252+
* Get the <em>repeatable</em> {@link Annotation}s of {@code annotationType}
253+
* from the supplied {@link AnnotatedElement}, where such annotations are
254+
* either <em>present</em> or <em>meta-present</em> on the element.
255+
* <p>Handles both single annotations and annotations nested within a
256+
* <em>containing annotation</em>.
246257
* <p>Meta-annotations will be searched if the annotation is not
247-
* <em>directly present</em> on the supplied element.
248-
* @param annotatedElement the element to look for annotations on
249-
* @param containerAnnotationType the class of the container that holds the annotations
258+
* <em>present</em> on the supplied element.
259+
* @param annotatedElement the element to look for annotations on; never {@code null}
260+
* @param containerAnnotationType the type of the container that holds the
261+
* annotations; may be {@code null} if a container is not supported
250262
* @param annotationType the annotation type to look for
251263
* @return the annotations found or an empty set; never {@code null}
252264
* @since 4.0
@@ -328,7 +340,8 @@ private static <A extends Annotation> A findAnnotation(AnnotatedElement annotate
328340
/**
329341
* Find a single {@link Annotation} of {@code annotationType} on the supplied
330342
* {@link Method}, traversing its super methods (i.e., from superclasses and
331-
* interfaces) if no annotation can be found on the given method itself.
343+
* interfaces) if the annotation is not <em>directly present</em> on the given
344+
* method itself.
332345
* <p>Correctly handles bridge {@link Method Methods} generated by the compiler.
333346
* <p>Meta-annotations will be searched if the annotation is not
334347
* <em>directly present</em> on the method.
@@ -423,8 +436,8 @@ static boolean isInterfaceWithAnnotatedMethods(Class<?> iface) {
423436
/**
424437
* Find a single {@link Annotation} of {@code annotationType} on the
425438
* supplied {@link Class}, traversing its interfaces, annotations, and
426-
* superclasses if the annotation is not <em>present</em> on the given class
427-
* itself.
439+
* superclasses if the annotation is not <em>directly present</em> on
440+
* the given class itself.
428441
* <p>This method explicitly handles class-level annotations which are not
429442
* declared as {@link java.lang.annotation.Inherited inherited} <em>as well
430443
* as meta-annotations and annotations on interfaces</em>.
@@ -505,21 +518,22 @@ private static <A extends Annotation> A findAnnotation(Class<?> clazz, Class<A>
505518
}
506519

507520
/**
508-
* Find the first {@link Class} in the inheritance hierarchy of the specified {@code clazz}
509-
* (including the specified {@code clazz} itself) which declares an annotation for the
510-
* specified {@code annotationType}, or {@code null} if not found. If the supplied
511-
* {@code clazz} is {@code null}, {@code null} will be returned.
512-
* <p>If the supplied {@code clazz} is an interface, only the interface itself will be checked;
513-
* the inheritance hierarchy for interfaces will not be traversed.
521+
* Find the first {@link Class} in the inheritance hierarchy of the
522+
* specified {@code clazz} (including the specified {@code clazz} itself)
523+
* on which an annotation of the specified {@code annotationType} is
524+
* <em>directly present</em>.
525+
* <p>If the supplied {@code clazz} is an interface, only the interface
526+
* itself will be checked; the inheritance hierarchy for interfaces will
527+
* not be traversed.
514528
* <p>Meta-annotations will <em>not</em> be searched.
515-
* <p>The standard {@link Class} API does not provide a mechanism for determining which class
516-
* in an inheritance hierarchy actually declares an {@link Annotation}, so we need to handle
517-
* this explicitly.
518-
* @param annotationType the annotation type to look for, both locally and as a meta-annotation
519-
* @param clazz the class on which to check for the annotation (may be {@code null})
520-
* @return the first {@link Class} in the inheritance hierarchy of the specified {@code clazz}
521-
* which declares an annotation of the specified {@code annotationType}, or {@code null}
522-
* if not found
529+
* <p>The standard {@link Class} API does not provide a mechanism for
530+
* determining which class in an inheritance hierarchy actually declares
531+
* an {@link Annotation}, so we need to handle this explicitly.
532+
* @param annotationType the annotation type to look for
533+
* @param clazz the class to check for the annotation on (may be {@code null})
534+
* @return the first {@link Class} in the inheritance hierarchy that
535+
* declares an annotation of the specified {@code annotationType}, or
536+
* {@code null} if not found
523537
* @see Class#isAnnotationPresent(Class)
524538
* @see Class#getDeclaredAnnotations()
525539
* @see #findAnnotationDeclaringClassForTypes(List, Class)
@@ -537,25 +551,22 @@ public static Class<?> findAnnotationDeclaringClass(Class<? extends Annotation>
537551
}
538552

539553
/**
540-
* Find the first {@link Class} in the inheritance hierarchy of the specified
541-
* {@code clazz} (including the specified {@code clazz} itself) which declares
542-
* at least one of the specified {@code annotationTypes}, or {@code null} if
543-
* none of the specified annotation types could be found.
544-
* <p>If the supplied {@code clazz} is {@code null}, {@code null} will be
545-
* returned.
546-
* <p>If the supplied {@code clazz} is an interface, only the interface itself
547-
* will be checked; the inheritance hierarchy for interfaces will not be traversed.
554+
* Find the first {@link Class} in the inheritance hierarchy of the
555+
* specified {@code clazz} (including the specified {@code clazz} itself)
556+
* on which at least one of the specified {@code annotationTypes} is
557+
* <em>directly present</em>.
558+
* <p>If the supplied {@code clazz} is an interface, only the interface
559+
* itself will be checked; the inheritance hierarchy for interfaces will
560+
* not be traversed.
548561
* <p>Meta-annotations will <em>not</em> be searched.
549-
* <p>The standard {@link Class} API does not provide a mechanism for determining
550-
* which class in an inheritance hierarchy actually declares one of several
551-
* candidate {@linkplain Annotation annotations}, so we need to handle this
552-
* explicitly.
553-
* @param annotationTypes the list of Class objects corresponding to the
554-
* annotation types
555-
* @param clazz the Class object corresponding to the class on which to check
556-
* for the annotations, or {@code null}
557-
* @return the first {@link Class} in the inheritance hierarchy of the specified
558-
* {@code clazz} which declares an annotation of at least one of the specified
562+
* <p>The standard {@link Class} API does not provide a mechanism for
563+
* determining which class in an inheritance hierarchy actually declares
564+
* one of several candidate {@linkplain Annotation annotations}, so we
565+
* need to handle this explicitly.
566+
* @param annotationTypes the annotation types to look for
567+
* @param clazz the class to check for the annotations on, or {@code null}
568+
* @return the first {@link Class} in the inheritance hierarchy that
569+
* declares an annotation of at least one of the specified
559570
* {@code annotationTypes}, or {@code null} if not found
560571
* @since 3.2.2
561572
* @see Class#isAnnotationPresent(Class)
@@ -577,54 +588,56 @@ public static Class<?> findAnnotationDeclaringClassForTypes(List<Class<? extends
577588
}
578589

579590
/**
580-
* Determine whether an annotation of the specified {@code annotationType} is
581-
* declared locally (i.e., <em>directly present</em>) on the supplied
582-
* {@code clazz}. The supplied {@link Class} may represent any type.
591+
* Determine whether an annotation of the specified {@code annotationType}
592+
* is declared locally (i.e., <em>directly present</em>) on the supplied
593+
* {@code clazz}.
594+
* <p>The supplied {@link Class} may represent any type.
583595
* <p>Meta-annotations will <em>not</em> be searched.
584-
* <p>Note: This method does <strong>not</strong> determine if the annotation is
585-
* {@linkplain java.lang.annotation.Inherited inherited}. For greater clarity
586-
* regarding inherited annotations, consider using
596+
* <p>Note: This method does <strong>not</strong> determine if the annotation
597+
* is {@linkplain java.lang.annotation.Inherited inherited}. For greater
598+
* clarity regarding inherited annotations, consider using
587599
* {@link #isAnnotationInherited(Class, Class)} instead.
588-
* @param annotationType the Class object corresponding to the annotation type
589-
* @param clazz the Class object corresponding to the class on which to check for the annotation
600+
* @param annotationType the annotation type to look for
601+
* @param clazz the class to check for the annotation on
590602
* @return {@code true} if an annotation of the specified {@code annotationType}
591-
* is <em>directly present</em> on the supplied {@code clazz}
603+
* is <em>directly present</em>
592604
* @see java.lang.Class#getDeclaredAnnotations()
593605
* @see java.lang.Class#getDeclaredAnnotation(Class)
594606
* @see #isAnnotationInherited(Class, Class)
595607
*/
596608
public static boolean isAnnotationDeclaredLocally(Class<? extends Annotation> annotationType, Class<?> clazz) {
597609
Assert.notNull(annotationType, "Annotation type must not be null");
598610
Assert.notNull(clazz, "Class must not be null");
599-
boolean declaredLocally = false;
600611
try {
601612
for (Annotation ann : clazz.getDeclaredAnnotations()) {
602613
if (ann.annotationType().equals(annotationType)) {
603-
declaredLocally = true;
604-
break;
614+
return true;
605615
}
606616
}
607617
}
608618
catch (Exception ex) {
609619
// Assuming nested Class values not resolvable within annotation attributes...
610620
logIntrospectionFailure(clazz, ex);
611621
}
612-
return declaredLocally;
622+
return false;
613623
}
614624

615625
/**
616-
* Determine whether an annotation of the specified {@code annotationType} is <em>present</em>
617-
* on the supplied {@code clazz} and is {@linkplain java.lang.annotation.Inherited inherited}
618-
* (i.e., not declared locally for the class).
626+
* Determine whether an annotation of the specified {@code annotationType}
627+
* is <em>present</em> on the supplied {@code clazz} and is
628+
* {@linkplain java.lang.annotation.Inherited inherited} (i.e., not
629+
* <em>directly present</em>).
619630
* <p>Meta-annotations will <em>not</em> be searched.
620-
* <p>If the supplied {@code clazz} is an interface, only the interface itself will be checked.
621-
* In accordance with standard meta-annotation semantics, the inheritance hierarchy for interfaces
622-
* will not be traversed. See the {@linkplain java.lang.annotation.Inherited Javadoc} for the
623-
* {@code @Inherited} meta-annotation for further details regarding annotation inheritance.
624-
* @param annotationType the Class object corresponding to the annotation type
625-
* @param clazz the Class object corresponding to the class on which to check for the annotation
626-
* @return {@code true} if an annotation of the specified {@code annotationType} is present
627-
* on the supplied {@code clazz} and is <em>inherited</em>
631+
* <p>If the supplied {@code clazz} is an interface, only the interface
632+
* itself will be checked. In accordance with standard meta-annotation
633+
* semantics in Java, the inheritance hierarchy for interfaces will not
634+
* be traversed. See the {@linkplain java.lang.annotation.Inherited Javadoc}
635+
* for the {@code @Inherited} meta-annotation for further details regarding
636+
* annotation inheritance.
637+
* @param annotationType the annotation type to look for
638+
* @param clazz the class to check for the annotation on
639+
* @return {@code true} if an annotation of the specified {@code annotationType}
640+
* is <em>present</em> and <em>inherited</em>
628641
* @see Class#isAnnotationPresent(Class)
629642
* @see #isAnnotationDeclaredLocally(Class, Class)
630643
*/

0 commit comments

Comments
 (0)