blob: 351e3a94b3f02bb20794e6475045dcb3ca13582d [file] [log] [blame]
Orion Hodson58143d22018-02-20 08:44:20 +00001/*
2 * Copyright (C) 2018 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
17import java.lang.annotation.Annotation;
18import java.lang.annotation.Retention;
19import java.lang.annotation.RetentionPolicy;
20import java.lang.reflect.Constructor;
21import java.lang.reflect.Parameter;
22
23public class Main {
24 // A simple parameter annotation
25 @Retention(RetentionPolicy.RUNTIME)
26 public @interface AnnotationA {}
27
28 // A parameter annotation with additional state
29 @Retention(RetentionPolicy.RUNTIME)
30 public @interface AnnotationB {
31 String value() default "default-value";
32 }
33
34 // An inner class whose constructors with have an implicit
35 // argument for the enclosing instance.
36 public class Inner {
37 private final int number;
38 private final String text;
39 boolean flag;
40
41 Inner(@AnnotationA int number, String text) {
42 this.number = number;
43 this.text = text;
44 this.flag = false;
45 }
46
47 Inner(@AnnotationA int number, String text, @AnnotationB("x") boolean flag) {
48 this.number = number;
49 this.text = text;
50 this.flag = flag;
51 }
52 }
53
54 // An inner class whose constructors with have no implicit
55 // arguments for the enclosing instance.
56 public static class StaticInner {
57 private final int number;
58 private final String text;
59 boolean flag;
60
61 StaticInner(@AnnotationA int number, String text) {
62 this.number = number;
63 this.text = text;
64 this.flag = false;
65 }
66
67 StaticInner(@AnnotationB("foo") int number, String text, @AnnotationA boolean flag) {
68 this.number = number;
69 this.text = text;
70 this.flag = flag;
71 }
72 }
73
74 public enum ImportantNumber {
75 ONE(1.0),
76 TWO(2.0),
77 MANY(3.0, true);
78
79 private double doubleValue;
80 private boolean isLarge;
81
82 ImportantNumber(@AnnotationA double doubleValue) {
83 this.doubleValue = doubleValue;
84 this.isLarge = false;
85 }
86
87 ImportantNumber(@AnnotationB("x") double doubleValue, @AnnotationB("y") boolean isLarge) {
88 this.doubleValue = doubleValue;
89 this.isLarge = isLarge;
90 }
91 }
92
93 public enum BinaryNumber {
94 ZERO,
95 ONE;
96 }
97
98 private abstract static class AnonymousBase {
99 public AnonymousBase(@AnnotationA String s) {}
100 }
101
102 private static String annotationToNormalizedString(Annotation annotation) {
103 // String.replace() to accomodate different representation across VMs.
104 return annotation.toString().replace("\"", "");
105 }
106
107 private static void DumpConstructorParameterAnnotations(Class<?> cls) throws Throwable {
108 System.out.println(cls.getName());
109 for (Constructor c : cls.getDeclaredConstructors()) {
110 System.out.println(" " + c);
111 Annotation[][] annotations = c.getParameterAnnotations();
112 Parameter[] parameters = c.getParameters();
113 for (int i = 0; i < annotations.length; ++i) {
114 // Exercise java.lang.reflect.Executable.getParameterAnnotationsNative()
115 // which retrieves all annotations for the parameters.
116 System.out.print(" Parameter [" + i + "]:");
117 for (Annotation annotation : parameters[i].getAnnotations()) {
118 System.out.println(" Indexed : " + annotationToNormalizedString(annotation));
119 }
120 for (Annotation annotation : annotations[i]) {
121 System.out.println(" Array : " + annotationToNormalizedString(annotation));
122 }
123
124 // Exercise Parameter.getAnnotationNative() with
125 // retrieves a single parameter annotation according to type.
126 Object[] opaqueClasses = new Object[] {AnnotationA.class, AnnotationB.class};
127 for (Object opaqueClass : opaqueClasses) {
128 @SuppressWarnings("unchecked")
129 Class<? extends Annotation> annotationClass =
130 (Class<? extends Annotation>) opaqueClass;
131 Annotation annotation = parameters[i].getDeclaredAnnotation(annotationClass);
132 String hasAnnotation = (annotation != null ? "Yes" : "No");
133 System.out.println(" " + annotationClass.getName() + " " + hasAnnotation);
134
135 Annotation[] parameterAnnotations = parameters[i].getDeclaredAnnotationsByType(annotationClass);
136 for (Annotation parameterAnnotation : parameterAnnotations) {
137 System.out.println(" " + annotationToNormalizedString(parameterAnnotation));
138 }
139 }
140 }
141 }
142 }
143
144 private Class<?> getLocalClassWithEnclosingInstanceCapture() {
145 class LocalClass {
146 private final int integerValue;
147
148 LocalClass(@AnnotationA int integerValue) {
149 this.integerValue = integerValue;
150 }
151 }
152 return LocalClass.class;
153 }
154
155 private Class<?> getLocalClassWithEnclosingInstanceAndLocalCapture() {
156 final long CAPTURED_VALUE = System.currentTimeMillis();
157 class LocalClassWithCapture {
158 private final String value;
159 private final long capturedValue;
160
161 LocalClassWithCapture(@AnnotationA String p1) {
162 this.value = p1;
163 this.capturedValue = CAPTURED_VALUE;
164 }
165 }
166 return LocalClassWithCapture.class;
167 }
168
169 public static void main(String[] args) throws Throwable {
170 // A local class declared in a static context (0 implicit parameters).
171 class LocalClassStaticContext {
172 private final int value;
173
174 LocalClassStaticContext(@AnnotationA int p0) {
175 this.value = p0;
176 }
177 }
178
179 final long CAPTURED_VALUE = System.currentTimeMillis();
180 // A local class declared in a static context with a capture (1 implicit parameters).
181 class LocalClassStaticContextWithCapture {
182 private final long capturedValue;
183 private final String argumentValue;
184
185 LocalClassStaticContextWithCapture(@AnnotationA String p1) {
186 this.capturedValue = CAPTURED_VALUE;
187 this.argumentValue = p1;
188 }
189 }
190
191 // Another local class declared in a static context with a capture (1 implicit parameters).
192 class LocalClassStaticContextWithCaptureAlternateOrdering {
193 private final String argumentValue;
194 private final long capturedValue;
195
196 LocalClassStaticContextWithCaptureAlternateOrdering(@AnnotationA String p1) {
197 this.argumentValue = p1;
198 this.capturedValue = CAPTURED_VALUE;
199 }
200 }
201
202 DumpConstructorParameterAnnotations(Main.class);
203 DumpConstructorParameterAnnotations(LocalClassStaticContext.class);
204 DumpConstructorParameterAnnotations(LocalClassStaticContextWithCapture.class);
205 DumpConstructorParameterAnnotations(LocalClassStaticContextWithCaptureAlternateOrdering.class);
206 Main m = new Main();
207 DumpConstructorParameterAnnotations(m.getLocalClassWithEnclosingInstanceCapture());
208 DumpConstructorParameterAnnotations(m.getLocalClassWithEnclosingInstanceAndLocalCapture());
209 DumpConstructorParameterAnnotations(Inner.class);
210 DumpConstructorParameterAnnotations(StaticInner.class);
211 DumpConstructorParameterAnnotations(ImportantNumber.class);
212 DumpConstructorParameterAnnotations(BinaryNumber.class);
213 DumpConstructorParameterAnnotations(new AnonymousBase("") {}.getClass());
214 }
215}