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    */
getDirectOrIndirectAnnotationsByType( AnnotatedElement element, Class<T> annotationClass)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    */
insertAnnotationValues(Annotation annotation, Class<T> annotationClass, ArrayList<T> unfoldedAnnotations)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>
getRepeatableAnnotationContainerClassFor(Class<T> annotationClass)149       getRepeatableAnnotationContainerClassFor(Class<T> annotationClass) {
150 
151     Repeatable repeatableAnnotation = annotationClass.getDeclaredAnnotation(Repeatable.class);
152     return (repeatableAnnotation == null) ? null : repeatableAnnotation.value();
153   }
154 
AnnotatedElements()155   private AnnotatedElements() {
156   }
157 }
158 
159