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. *