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