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 import java.lang.annotation.Annotation;
18 import java.lang.reflect.Method;
19 
20 public class AnnotationTest extends AnnotationTestHelpers {
testAnnotationsByType()21   public static void testAnnotationsByType() {
22     System.out.println("==============================");
23     System.out.println("Class annotations by type:");
24     System.out.println("==============================");
25 
26     // Print associated annotations:
27     // * A is directly present or repeatably present on an element E;
28     // * No annotation of A is directly/repeatably present on an element
29     //   AND E is a class AND A's type is inheritable, AND A is associated with its superclass.
30     // (Looks through subtypes recursively only if there's 0 result at each level,
31     // and the annotation is @Inheritable).
32     printAnnotationsByType(Calendar.class, SingleUser.class);
33     printAnnotationsByType(Calendars.class, SingleUser.class);
34 
35     printAnnotationsByType(Calendar.class, User.class);
36     printAnnotationsByType(Calendars.class, User.class);
37 
38     printAnnotationsByType(Calendar.class, User2.class);  // Enforce ordering 'z,x,y'
39     printAnnotationsByType(Calendars.class, User2.class);
40 
41     // NOTE:
42     //    Order of outer-most annotations Calendars[C,C],S vs C,Calendars[C,C] is unspecified.
43     //    In particular it's the order of #getDeclaredAnnotations which is completely unmentioned.
44     //    The only requirement for #getAnnotationsByType is to have same ordering as
45     //    #getDeclaredAnnotations.
46     //    (Calendars[] itself has to maintain value() order).
47     printAnnotationsByType(Calendar.class, UserComplex.class);  // Cs(C,C),C collapses into C,C,C.
48     printAnnotationsByType(Calendars.class, UserComplex.class);
49 
50     printAnnotationsByType(Calendar.class, UserSub.class);
51     printAnnotationsByType(Calendars.class, UserSub.class);
52 
53     printAnnotationsByType(Calendar.class, UserSub2.class);
54     // The directly present "Calendar" annotation masks all the repeatably present
55     // "Calendar" annotations coming from User.
56     printAnnotationsByType(Calendars.class, UserSub2.class);
57     // Edge case: UserSub2 doesn't directly have a Calendars annotation,
58     // so it doesn't mask the "User" Calendars annotation.
59 
60     System.out.println("-----------------------------");
61     System.out.println("-----------------------------");
62 
63   }
64 
testDeclaredAnnotation()65   public static void testDeclaredAnnotation() {
66     System.out.println("==============================");
67     System.out.println("Class declared annotation:");
68     System.out.println("==============================");
69 
70     // Print directly present annotations:
71     //
72     // The element E has an annotation_item for it (accessible through an
73     // annotations_directory_item) corresponding to an annotation A,
74     // and A's type_idx must match that on the encoded_annotation (from the annotation_item).
75     // (Does not look through the subtypes recursively)
76     printDeclaredAnnotation(SingleUser.class, Calendar.class);
77     printDeclaredAnnotation(SingleUser.class, Calendars.class);
78 
79     printDeclaredAnnotation(User.class, Calendar.class);
80     printDeclaredAnnotation(User.class, Calendars.class);
81 
82     printDeclaredAnnotation(UserComplex.class, Calendar.class);
83     printDeclaredAnnotation(UserComplex.class, Calendars.class);
84 
85     printDeclaredAnnotation(UserSub.class, Calendar.class);
86     printDeclaredAnnotation(UserSub.class, Calendars.class);
87 
88     printDeclaredAnnotation(UserSub2.class, Calendar.class);
89     printDeclaredAnnotation(UserSub2.class, Calendars.class);
90 
91     System.out.println("-----------------------------");
92     System.out.println("-----------------------------");
93   }
94 
testDeclaredAnnotationsByType()95   public static void testDeclaredAnnotationsByType() {
96     System.out.println("==============================");
97     System.out.println("Declared class annotations by type:");
98     System.out.println("==============================");
99 
100     // A is directly present or repeatably present on an element E;
101     // -- (does not do any recursion for classes regardless of @Inherited)
102     printDeclaredAnnotationsByType(Calendar.class, SingleUser.class);
103     printDeclaredAnnotationsByType(Calendars.class, SingleUser.class);
104 
105     printDeclaredAnnotationsByType(Calendar.class, User.class);
106     printDeclaredAnnotationsByType(Calendars.class, User.class);
107 
108     printDeclaredAnnotationsByType(Calendar.class, User2.class);  // Enforce ordering 'z,x,y'
109     printDeclaredAnnotationsByType(Calendars.class, User2.class);
110 
111     printDeclaredAnnotationsByType(Calendar.class, UserComplex.class);
112     printDeclaredAnnotationsByType(Calendars.class, UserComplex.class);
113 
114     printDeclaredAnnotationsByType(Calendar.class, UserSub.class);
115     printDeclaredAnnotationsByType(Calendars.class, UserSub.class);
116 
117     printDeclaredAnnotationsByType(Calendar.class, UserSub2.class);
118     // The directly present "Calendar" annotation masks all the repeatably present "Calendar"
119     // annotations coming from User.
120     printDeclaredAnnotationsByType(Calendars.class, UserSub2.class);
121     // Edge case: UserSub2 doesn't directly have a Calendars annotation,
122     // so it doesn't mask the "User" Calendars annotation.
123 
124     System.out.println("-----------------------------");
125     System.out.println("-----------------------------");
126   }
127 
128   // Print the annotation "annotationClass" that is associated with an element denoted by
129   // "annotationUseClass."
printAnnotationsByType(Class<A> annotationClass, Class<?> annotationUseClass)130   private static <A extends Annotation> void printAnnotationsByType(Class<A> annotationClass,
131       Class<?> annotationUseClass) {
132     A[] annotationsByType = annotationUseClass.getAnnotationsByType(annotationClass);
133 
134     String msg = "Annotations by type, defined by class "
135         + annotationUseClass.getName() + " with annotation " + annotationClass.getName() + ": "
136         + asString(annotationsByType);
137 
138 
139     System.out.println(msg);
140   }
141 
printDeclaredAnnotation(Class<?> annotationUseClass, Class<A> annotationDefClass)142   private static <A extends Annotation> void printDeclaredAnnotation(Class<?> annotationUseClass,
143       Class<A> annotationDefClass) {
144     A anno = annotationUseClass.getDeclaredAnnotation(annotationDefClass);
145 
146     String msg = asString(anno);
147 
148     System.out.println("Declared annotations by class " + annotationUseClass
149         + ", annotation " + annotationDefClass + ": " + msg);
150   }
151 
152   // Print the annotation "annotationClass" that is directly/indirectly present with an element
153   // denoted by "annotationUseClass."
printDeclaredAnnotationsByType( Class<A> annotationClass, Class<?> annotationUseClass)154   private static <A extends Annotation> void printDeclaredAnnotationsByType(
155       Class<A> annotationClass, Class<?> annotationUseClass) {
156     A[] annotationsByType = annotationUseClass.getDeclaredAnnotationsByType(annotationClass);
157 
158     String msg = "Declared annnotations by type, defined by class " + annotationUseClass.getName()
159         + " with annotation " + annotationClass.getName() + ": "
160         + asString(annotationsByType);
161 
162     System.out.println(msg);
163   }
164 
testMethodAnnotationsByType()165   public static void testMethodAnnotationsByType() {
166     System.out.println("==============================");
167     System.out.println("Method annotations by type:");
168     System.out.println("==============================");
169 
170     // Print associated annotations:
171     // * A is directly present or repeatably present on an element E;
172     // * No annotation of A is directly/repeatably present on an element AND E is a class
173     //   AND A's type is inheritable, AND A is associated with its superclass.
174     // (Looks through subtypes recursively only if there's 0 result at each level,
175     // and the annotation is @Inheritable).
176     printMethodAnnotationsByType(Calendar.class, "singleUser", AnnotationTestFixture.class);
177     printMethodAnnotationsByType(Calendars.class, "singleUser", AnnotationTestFixture.class);
178 
179     printMethodAnnotationsByType(Calendar.class, "user", AnnotationTestFixture.class);
180     printMethodAnnotationsByType(Calendars.class, "user", AnnotationTestFixture.class);
181 
182     printMethodAnnotationsByType(Calendar.class, "user2", AnnotationTestFixture.class);
183     printMethodAnnotationsByType(Calendars.class, "user2", AnnotationTestFixture.class);
184 
185     printMethodAnnotationsByType(Calendar.class, "userComplex", AnnotationTestFixture.class);
186     printMethodAnnotationsByType(Calendars.class, "userComplex", AnnotationTestFixture.class);
187 
188     System.out.println("-----------------------------");
189     System.out.println("-----------------------------");
190   }
191 
192   // Print the annotation "annotationClass" that is associated with an element denoted by
193   // "annotationUseClass" method methodName.
printMethodAnnotationsByType(Class<A> annotationClass, String methodName, Class<?> annotationUseClass)194   private static <A extends Annotation> void printMethodAnnotationsByType(Class<A> annotationClass,
195       String methodName, Class<?> annotationUseClass) {
196     Method m = null;
197     try {
198       m = annotationUseClass.getDeclaredMethod(methodName);
199     } catch (Throwable t) {
200       throw new AssertionError(t);
201     }
202     A[] annotationsByType = m.getAnnotationsByType(annotationClass);
203 
204     String msg = "Annotations by type, defined by method " + m.getName() + " with annotation " +
205       annotationClass.getName() + ": " +
206       asString(annotationsByType);
207 
208     System.out.println(msg);
209   }
210 
testMethodDeclaredAnnotations()211   public static void testMethodDeclaredAnnotations() {
212     System.out.println("==============================");
213     System.out.println("Declared method annotations:");
214     System.out.println("==============================");
215 
216     printMethodDeclaredAnnotation(Calendar.class, "singleUser", AnnotationTestFixture.class);
217     printMethodDeclaredAnnotation(Calendars.class, "singleUser", AnnotationTestFixture.class);
218 
219     printMethodDeclaredAnnotation(Calendar.class, "user", AnnotationTestFixture.class);
220     printMethodDeclaredAnnotation(Calendars.class, "user", AnnotationTestFixture.class);
221 
222     printMethodDeclaredAnnotation(Calendar.class, "user2", AnnotationTestFixture.class);
223     printMethodDeclaredAnnotation(Calendars.class, "user2", AnnotationTestFixture.class);
224 
225     printMethodDeclaredAnnotation(Calendar.class, "userComplex", AnnotationTestFixture.class);
226     printMethodDeclaredAnnotation(Calendars.class, "userComplex", AnnotationTestFixture.class);
227 
228     System.out.println("-----------------------------");
229     System.out.println("-----------------------------");
230   }
231 
232   // Print the annotation "annotationClass" that is associated with an element denoted by
233   // methodName in annotationUseClass.
printMethodDeclaredAnnotation(Class<A> annotationClass, String methodName, Class<?> annotationUseClass)234   private static <A extends Annotation> void printMethodDeclaredAnnotation(Class<A> annotationClass,
235       String methodName, Class<?> annotationUseClass) {
236     Method m = null;
237     try {
238       m = annotationUseClass.getDeclaredMethod(methodName);
239     } catch (Throwable t) {
240       throw new AssertionError(t);
241     }
242     Annotation annotationsByType = m.getDeclaredAnnotation(annotationClass);
243 
244     String msg = "Annotations declared by method " + m.getName() + " with annotation "
245         + annotationClass.getName() + ": "
246         + asString(annotationsByType);
247 
248     System.out.println(msg);
249   }
250 
testMethodDeclaredAnnotationsByType()251   public static void testMethodDeclaredAnnotationsByType() {
252     System.out.println("==============================");
253     System.out.println("Declared method annotations by type:");
254     System.out.println("==============================");
255 
256     printMethodDeclaredAnnotationByType(Calendar.class, "singleUser", AnnotationTestFixture.class);
257     printMethodDeclaredAnnotationByType(Calendars.class, "singleUser", AnnotationTestFixture.class);
258 
259     printMethodDeclaredAnnotationByType(Calendar.class, "user", AnnotationTestFixture.class);
260     printMethodDeclaredAnnotationByType(Calendars.class, "user", AnnotationTestFixture.class);
261 
262     printMethodDeclaredAnnotationByType(Calendar.class, "user2", AnnotationTestFixture.class);
263     printMethodDeclaredAnnotationByType(Calendars.class, "user2", AnnotationTestFixture.class);
264 
265     printMethodDeclaredAnnotationByType(Calendar.class, "userComplex", AnnotationTestFixture.class);
266     printMethodDeclaredAnnotationByType(Calendars.class, "userComplex",
267         AnnotationTestFixture.class);
268 
269     System.out.println("-----------------------------");
270     System.out.println("-----------------------------");
271   }
272 
273   // Print the annotation "annotationClass" that is associated with an element denoted by
274   // methodName in annotationUseClass.
printMethodDeclaredAnnotationByType( Class<A> annotationClass, String methodName, Class<?> annotationUseClass)275   private static <A extends Annotation> void printMethodDeclaredAnnotationByType(
276       Class<A> annotationClass, String methodName, Class<?> annotationUseClass) {
277     Method m = null;
278     try {
279       m = annotationUseClass.getDeclaredMethod(methodName);
280     } catch (Throwable t) {
281       throw new AssertionError(t);
282     }
283     A[] annotationsByType = m.getDeclaredAnnotationsByType(annotationClass);
284 
285     String msg = "Annotations by type, defined by method " + m.getName() + " with annotation "
286         + annotationClass.getName() + ": "
287         + asString(annotationsByType);
288 
289     System.out.println(msg);
290   }
291 }
292