Home | History | Annotate | Download | only in reflect
      1 /*
      2  * Copyright (C) 2016 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 package libcore.reflect;
     18 
     19 import java.lang.annotation.Annotation;
     20 import java.lang.annotation.IncompleteAnnotationException;
     21 import java.lang.annotation.Repeatable;
     22 import java.lang.reflect.*;
     23 import java.util.ArrayList;
     24 
     25 /**
     26  * Implementation of {@link AnnotatedElement}'s 1.8 methods.
     27  *
     28  * <p>This implementation is shared between all the classes implementing {@link AnnotatedElement},
     29  * avoiding code duplication.</p>
     30  *
     31  * @hide
     32  */
     33 public final class AnnotatedElements {
     34   /**
     35    * Default implementation of {@link AnnotatedElement#getDeclaredAnnotationsByType}, and
     36    * {@link AnnotatedElement#getAnnotationsByType} for elements that do not support annotation
     37    * inheritance.
     38    *
     39    * @return Directly/indirectly present list of annotations of type {@code annotationClass} for
     40    *         {@code element}, or an empty array if none were found.
     41    */
     42   public static <T extends Annotation> T[] getDirectOrIndirectAnnotationsByType(
     43         AnnotatedElement element, Class<T> annotationClass) {
     44     if (annotationClass == null) {
     45       throw new NullPointerException("annotationClass");
     46     }
     47 
     48     Annotation[] annotations = element.getDeclaredAnnotations();
     49 
     50     // Store a list of repeatable annotations that have been extracted from their container.
     51     ArrayList<T> unfoldedAnnotations = new ArrayList<T>();
     52 
     53     Class<? extends Annotation> repeatableAnnotationClass =
     54         getRepeatableAnnotationContainerClassFor(annotationClass);
     55 
     56     for (int i = 0; i < annotations.length; ++i) {
     57       if (annotationClass.isInstance(annotations[i])) {
     58         // Is it directly present?
     59         unfoldedAnnotations.add((T)annotations[i]);  // Safe, guarded by above check.
     60       } else if (repeatableAnnotationClass != null &&
     61           repeatableAnnotationClass.isInstance(annotations[i])) {
     62         // Is it repeatably (indirectly) present?
     63         insertAnnotationValues(annotations[i], annotationClass, unfoldedAnnotations);
     64       }
     65     }
     66 
     67     return unfoldedAnnotations.toArray((T[])Array.newInstance(annotationClass, 0));
     68   }
     69 
     70   /**
     71    * Extracts annotations from a container annotation and inserts them into a list.
     72    *
     73    * <p>
     74    * Given a complex annotation "annotation", it should have a "T[] value()" method on it.
     75    * Call that method and add all of the nested annotations into unfoldedAnnotations list.
     76    * </p>
     77    */
     78   private static <T extends Annotation> void insertAnnotationValues(Annotation annotation,
     79       Class<T> annotationClass, ArrayList<T> unfoldedAnnotations) {
     80     // annotation is a complex annotation which has elements of instance annotationClass
     81     // (whose static type is T).
     82     //
     83     // @interface SomeName {  <--- = annotation.getClass()
     84     //   ...
     85     //   T[] value();        <--- T.class == annotationClass
     86     // }
     87     //
     88     // Use reflection to access these values.
     89     Class<T[]> annotationArrayClass =
     90         (Class<T[]>)((T[])Array.newInstance(annotationClass, 0)).getClass();
     91 
     92     Method valuesMethod;
     93     try {
     94       valuesMethod = annotation.getClass().getDeclaredMethod("value");
     95       // This will always succeed unless the annotation and its repeatable annotation class were
     96       // recompiled separately, then this is a binary incompatibility error.
     97     } catch (NoSuchMethodException e) {
     98       throw new AssertionError("annotation container = " + annotation +
     99           "annotation element class = " + annotationClass + "; missing value() method");
    100     } catch (SecurityException e) {
    101       throw new IncompleteAnnotationException(annotation.getClass(), "value");
    102     }
    103 
    104     // Ensure that value() returns a T[]
    105     if (!valuesMethod.getReturnType().isArray()) {
    106       throw new AssertionError("annotation container = " + annotation +
    107           "annotation element class = " + annotationClass + "; value() doesn't return array");
    108     }
    109 
    110     // Ensure that the T[] value() is actually the correct type (T==annotationClass).
    111     if (!annotationClass.equals(valuesMethod.getReturnType().getComponentType())) {
    112       throw new AssertionError("annotation container = " + annotation +
    113           "annotation element class = " + annotationClass + "; value() returns incorrect type");
    114     }
    115 
    116     // Append those values into the existing list.
    117     T[] nestedAnnotations;
    118     try {
    119       nestedAnnotations = (T[])valuesMethod.invoke(annotation);  // Safe because of #getMethod.
    120     } catch (IllegalAccessException|InvocationTargetException e) {
    121       throw new AssertionError(e);
    122     }
    123 
    124     for (int i = 0; i < nestedAnnotations.length; ++i) {
    125       unfoldedAnnotations.add(nestedAnnotations[i]);
    126     }
    127   }
    128 
    129   /**
    130    * Find the {@code \@Repeatable} container annotation class for an annotation class, or
    131    * {@code null}.
    132    *
    133    * <p>
    134    * Given:
    135    *
    136    * <code>
    137    *  @Repeatable(X.class)
    138    *  @interface SomeName {     <--- = annotationClass
    139    *  }...
    140    * </code>
    141    *
    142    * <p>
    143    * Returns {@code X.class}
    144    *
    145    * Otherwise if there was no {@code \@Repeatable} annotation, return {@code null}.
    146    * </p>
    147    */
    148   private static <T extends Annotation> Class<? extends Annotation>
    149       getRepeatableAnnotationContainerClassFor(Class<T> annotationClass) {
    150 
    151     Repeatable repeatableAnnotation = annotationClass.getDeclaredAnnotation(Repeatable.class);
    152     return (repeatableAnnotation == null) ? null : repeatableAnnotation.value();
    153   }
    154 
    155   private AnnotatedElements() {
    156   }
    157 }
    158 
    159