src/share/classes/java/lang/reflect/AnnotatedElement.java
Print this page
*** 25,34 ****
--- 25,38 ----
package java.lang.reflect;
import java.lang.annotation.Annotation;
import java.lang.annotation.AnnotationFormatError;
+ import java.lang.annotation.Repeatable;
+ import java.util.Objects;
+ import sun.reflect.annotation.AnnotationSupport;
+ import sun.reflect.annotation.AnnotationType;
/**
* Represents an annotated element of the program currently running in this
* VM. This interface allows annotations to be read reflectively. All
* annotations returned by methods in this interface are immutable and
*** 220,255 ****
* annotation.
*
* The caller of this method is free to modify the returned array; it will
* have no effect on the arrays returned to other callers.
*
* @param <T> the type of the annotation to query for and return if present
* @param annotationClass the Class object corresponding to the
* annotation type
* @return all this element's annotations for the specified annotation type if
* associated with this element, else an array of length zero
* @throws NullPointerException if the given annotation class is null
* @since 1.8
*/
! <T extends Annotation> T[] getAnnotationsByType(Class<T> annotationClass);
/**
* Returns this element's annotation for the specified type if
* such an annotation is <em>directly present</em>, else null.
*
* This method ignores inherited annotations. (Returns null if no
* annotations are directly present on this element.)
*
* @param <T> the type of the annotation to query for and return if directly present
* @param annotationClass the Class object corresponding to the
* annotation type
* @return this element's annotation for the specified annotation type if
* directly present on this element, else null
* @throws NullPointerException if the given annotation class is null
* @since 1.8
*/
! <T extends Annotation> T getDeclaredAnnotation(Class<T> annotationClass);
/**
* Returns this element's annotation(s) for the specified type if
* such annotations are either <em>directly present</em> or
* <em>indirectly present</em>. This method ignores inherited
--- 224,307 ----
* annotation.
*
* The caller of this method is free to modify the returned array; it will
* have no effect on the arrays returned to other callers.
*
+ * @implSpec The default implementation first calls {@link
+ * #getDeclaredAnnotationsByType(Class)} on the argument type. If
+ * the returned array has size greater than zero, the array is
+ * returned. If the returned array has size zero and this {@code
+ * AnnotatedElement} is a class and the argument type is an
+ * inheritable annotation, and the superclass of this {@code
+ * AnnoatedElement} is non-null, then the result of {@code
+ * getAnnotationsByType(annotationClass)} on the superclass is
+ * returned. Otherwise, a zero-length array is returned.
+ *
* @param <T> the type of the annotation to query for and return if present
* @param annotationClass the Class object corresponding to the
* annotation type
* @return all this element's annotations for the specified annotation type if
* associated with this element, else an array of length zero
* @throws NullPointerException if the given annotation class is null
* @since 1.8
*/
! default <T extends Annotation> T[] getAnnotationsByType(Class<T> annotationClass) {
! /*
! * Definition of associated: directly or indirectly present OR
! * neither directly nor indirectly present AND the element is
! * a Class, the annotation type is inheritable, and the
! * annotation type is associated with the superclass of the
! * element.
! */
! T[] result = getDeclaredAnnotationsByType(annotationClass);
!
! if (result.length == 0 && // Neither directly nor indirectly present
! this instanceof Class && // the element is a class
! AnnotationType.getInstance(annotationClass).isInherited()) { // Inheritable
! Class<?> clazz = ((Class<?>) this).getSuperclass();
! if (clazz != null) {
! // Determine if the annotation is associated with the
! // superclass
! result = clazz.getAnnotationsByType(annotationClass);
! }
! }
!
! return result;
! }
/**
* Returns this element's annotation for the specified type if
* such an annotation is <em>directly present</em>, else null.
*
* This method ignores inherited annotations. (Returns null if no
* annotations are directly present on this element.)
*
+ * @implSpec The default implementation first performs a null check
+ * and then loops over the results of {@link
+ * getDeclaredAnnotations} returning the first annotation whose
+ * annotation type matches the argument type.
+ *
* @param <T> the type of the annotation to query for and return if directly present
* @param annotationClass the Class object corresponding to the
* annotation type
* @return this element's annotation for the specified annotation type if
* directly present on this element, else null
* @throws NullPointerException if the given annotation class is null
* @since 1.8
*/
! default <T extends Annotation> T getDeclaredAnnotation(Class<T> annotationClass) {
! Objects.requireNonNull(annotationClass);
! // Loop over all directly-present annotations looking for a matching one
! for (Annotation annotation : getDeclaredAnnotations()) {
! if (annotationClass.equals(annotation.annotationType())) {
! // More robust to do a dynamic cast at runtime instead
! // of compile-time only.
! return annotationClass.cast(annotation);
! }
! }
! return null;
! }
/**
* Returns this element's annotation(s) for the specified type if
* such annotations are either <em>directly present</em> or
* <em>indirectly present</em>. This method ignores inherited
*** 266,285 ****
* through" a container annotation if one is present.
*
* The caller of this method is free to modify the returned array; it will
* have no effect on the arrays returned to other callers.
*
* @param <T> the type of the annotation to query for and return
* if directly or indirectly present
* @param annotationClass the Class object corresponding to the
* annotation type
* @return all this element's annotations for the specified annotation type if
* directly or indirectly present on this element, else an array of length zero
* @throws NullPointerException if the given annotation class is null
* @since 1.8
*/
! <T extends Annotation> T[] getDeclaredAnnotationsByType(Class<T> annotationClass);
/**
* Returns annotations that are <em>directly present</em> on this element.
* This method ignores inherited annotations.
*
--- 318,425 ----
* through" a container annotation if one is present.
*
* The caller of this method is free to modify the returned array; it will
* have no effect on the arrays returned to other callers.
*
+ * @implSpec The default implementation may call {@link
+ * #getDeclaredAnnotation(Class)} one or more times to find a
+ * directly present annotation and, if the annotation type is
+ * repeatable, to find a container annotation. If the annotation
+ * type is both directly and indirectly present, {@link
+ * getDeclaredAnnotations()} will get called to determine the
+ * order of the elements in the returned array. Alternatively,
+ * {@link getDeclaredAnnotations()} may be called a single time
+ * and the returned array examined for both directly and
+ * indirectly present annotations. The results of calling {@link
+ * getDeclaredAnnotations()} are assumed to be consistent with the
+ * results of calling {@code #getDeclaredAnnotation}
+ *
* @param <T> the type of the annotation to query for and return
* if directly or indirectly present
* @param annotationClass the Class object corresponding to the
* annotation type
* @return all this element's annotations for the specified annotation type if
* directly or indirectly present on this element, else an array of length zero
* @throws NullPointerException if the given annotation class is null
* @since 1.8
*/
! default <T extends Annotation> T[] getDeclaredAnnotationsByType(Class<T> annotationClass) {
! Objects.requireNonNull(annotationClass);
! int resultSize = 0;
! T directlyPresent = getDeclaredAnnotation(annotationClass);
! @SuppressWarnings("unchecked")
! T[] indirectlyPresent = (T[]) Array.newInstance(annotationClass, 0);
!
! if (directlyPresent != null) {
! resultSize++;
! }
!
! // If the annotation type is repeatable, look through a
! // container if one is present
! Repeatable repeatable = annotationClass.getAnnotation(Repeatable.class);
! Class<? extends Annotation> containerType = null;
! if (repeatable != null) { // T is a repeatable annotation type
! containerType = repeatable.value();
! Annotation container = this.getDeclaredAnnotation(containerType);
! if (container != null) {
! indirectlyPresent = AnnotationSupport.getValueArray(container);
! resultSize += indirectlyPresent.length;
! }
! }
!
! if (resultSize == indirectlyPresent.length) {
! assert resultSize == 0 || directlyPresent == null;
! /*
! * If resultSize is 0, indirectlyPresent is either
! * assigned to the result of the initial Array.newInstance
! * call or indirectlyPresent is assigned to a zero-length
! * value array from an empty container annotation. In
! * either case, a zero-length array is immutable and does
! * not need to reallocated before being returned.
! *
! * If resultSize is nonzero, then indirectlyPresent points
! * to the result calling a method on an annotation and
! * annotations are required to implement a no sharing
! * policy. Therefore, it is not required to copy the
! * elements of indirectlyPresent into a new array of the
! * same size.
! */
! return indirectlyPresent;
! } else {
! assert resultSize > 0 && (directlyPresent != null || indirectlyPresent.length > 0);
! @SuppressWarnings("unchecked")
! T[] returnValue = (T[]) Array.newInstance(annotationClass, resultSize);
!
! if (indirectlyPresent.length == 0) {
! assert resultSize == 1;
! returnValue[0] = directlyPresent;
! } else {
! assert directlyPresent != null && indirectlyPresent.length > 0;
! // Determine whether the directly present annotation
! // comes before or after the indirectly present ones.
!
! int indirectOffset = 0;
!
! for (Annotation a : getDeclaredAnnotations()) {
! if (a.annotationType().equals(annotationClass)) {
! indirectOffset = 1;
! break;
! } else if (a.annotationType().equals(containerType)) {
! break;
! }
! }
!
! for (int i = 0; i < resultSize; i++) {
! returnValue[i + indirectOffset] = indirectlyPresent[i];
! }
!
! returnValue[(indirectOffset == 1) ? 0 : resultSize - 1] = directlyPresent;
! }
! return returnValue;
! }
! }
!
/**
* Returns annotations that are <em>directly present</em> on this element.
* This method ignores inherited annotations.
*