Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
PojavLauncherTeam
GitHub Repository: PojavLauncherTeam/mobile
Path: blob/master/src/java.base/share/classes/sun/reflect/annotation/AnnotationSupport.java
41159 views
1
/*
2
* Copyright (c) 2012, 2021, Oracle and/or its affiliates. All rights reserved.
3
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4
*
5
* This code is free software; you can redistribute it and/or modify it
6
* under the terms of the GNU General Public License version 2 only, as
7
* published by the Free Software Foundation. Oracle designates this
8
* particular file as subject to the "Classpath" exception as provided
9
* by Oracle in the LICENSE file that accompanied this code.
10
*
11
* This code is distributed in the hope that it will be useful, but WITHOUT
12
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14
* version 2 for more details (a copy is included in the LICENSE file that
15
* accompanied this code).
16
*
17
* You should have received a copy of the GNU General Public License version
18
* 2 along with this work; if not, write to the Free Software Foundation,
19
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20
*
21
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22
* or visit www.oracle.com if you need additional information or have any
23
* questions.
24
*/
25
26
package sun.reflect.annotation;
27
28
import java.lang.annotation.*;
29
import java.lang.reflect.*;
30
import java.security.AccessController;
31
import java.security.PrivilegedAction;
32
import java.util.ArrayList;
33
import java.util.Arrays;
34
import java.util.List;
35
import java.util.Map;
36
import java.util.Objects;
37
38
import jdk.internal.access.SharedSecrets;
39
import jdk.internal.access.JavaLangAccess;
40
import jdk.internal.reflect.ReflectionFactory;
41
42
public final class AnnotationSupport {
43
private static final JavaLangAccess LANG_ACCESS = SharedSecrets.getJavaLangAccess();
44
45
/**
46
* Finds and returns all annotations in {@code annotations} matching
47
* the given {@code annoClass}.
48
*
49
* Apart from annotations directly present in {@code annotations} this
50
* method searches for annotations inside containers i.e. indirectly
51
* present annotations.
52
*
53
* The order of the elements in the array returned depends on the iteration
54
* order of the provided map. Specifically, the directly present annotations
55
* come before the indirectly present annotations if and only if the
56
* directly present annotations come before the indirectly present
57
* annotations in the map.
58
*
59
* @param annotations the {@code Map} in which to search for annotations
60
* @param annoClass the type of annotation to search for
61
*
62
* @return an array of instances of {@code annoClass} or an empty
63
* array if none were found
64
*/
65
public static <A extends Annotation> A[] getDirectlyAndIndirectlyPresent(
66
Map<Class<? extends Annotation>, Annotation> annotations,
67
Class<A> annoClass) {
68
List<A> result = new ArrayList<>();
69
70
@SuppressWarnings("unchecked")
71
A direct = (A) annotations.get(annoClass);
72
if (direct != null)
73
result.add(direct);
74
75
A[] indirect = getIndirectlyPresent(annotations, annoClass);
76
if (indirect != null && indirect.length != 0) {
77
boolean indirectFirst = direct == null ||
78
containerBeforeContainee(annotations, annoClass);
79
80
result.addAll((indirectFirst ? 0 : 1), Arrays.asList(indirect));
81
}
82
83
@SuppressWarnings("unchecked")
84
A[] arr = (A[]) Array.newInstance(annoClass, result.size());
85
return result.toArray(arr);
86
}
87
88
/**
89
* Finds and returns all annotations matching the given {@code annoClass}
90
* indirectly present in {@code annotations}.
91
*
92
* @param annotations annotations to search indexed by their types
93
* @param annoClass the type of annotation to search for
94
*
95
* @return an array of instances of {@code annoClass} or an empty array if no
96
* indirectly present annotations were found
97
*/
98
private static <A extends Annotation> A[] getIndirectlyPresent(
99
Map<Class<? extends Annotation>, Annotation> annotations,
100
Class<A> annoClass) {
101
102
Repeatable repeatable = annoClass.getDeclaredAnnotation(Repeatable.class);
103
if (repeatable == null)
104
return null; // Not repeatable -> no indirectly present annotations
105
106
Class<? extends Annotation> containerClass = repeatable.value();
107
108
Annotation container = annotations.get(containerClass);
109
if (container == null)
110
return null;
111
112
// Unpack container
113
A[] valueArray = getValueArray(container);
114
checkTypes(valueArray, container, annoClass);
115
116
return valueArray;
117
}
118
119
120
/**
121
* Figures out if container class comes before containee class among the
122
* keys of the given map.
123
*
124
* @return true if container class is found before containee class when
125
* iterating over annotations.keySet().
126
*/
127
private static <A extends Annotation> boolean containerBeforeContainee(
128
Map<Class<? extends Annotation>, Annotation> annotations,
129
Class<A> annoClass) {
130
131
Class<? extends Annotation> containerClass =
132
annoClass.getDeclaredAnnotation(Repeatable.class).value();
133
134
for (Class<? extends Annotation> c : annotations.keySet()) {
135
if (c == containerClass) return true;
136
if (c == annoClass) return false;
137
}
138
139
// Neither containee nor container present
140
return false;
141
}
142
143
144
/**
145
* Finds and returns all associated annotations matching the given class.
146
*
147
* The order of the elements in the array returned depends on the iteration
148
* order of the provided maps. Specifically, the directly present annotations
149
* come before the indirectly present annotations if and only if the
150
* directly present annotations come before the indirectly present
151
* annotations in the relevant map.
152
*
153
* @param declaredAnnotations the declared annotations indexed by their types
154
* @param decl the class declaration on which to search for annotations
155
* @param annoClass the type of annotation to search for
156
*
157
* @return an array of instances of {@code annoClass} or an empty array if none were found.
158
*/
159
public static <A extends Annotation> A[] getAssociatedAnnotations(
160
Map<Class<? extends Annotation>, Annotation> declaredAnnotations,
161
Class<?> decl,
162
Class<A> annoClass) {
163
Objects.requireNonNull(decl);
164
165
// Search declared
166
A[] result = getDirectlyAndIndirectlyPresent(declaredAnnotations, annoClass);
167
168
// Search inherited
169
if(AnnotationType.getInstance(annoClass).isInherited()) {
170
Class<?> superDecl = decl.getSuperclass();
171
while (result.length == 0 && superDecl != null) {
172
result = getDirectlyAndIndirectlyPresent(LANG_ACCESS.getDeclaredAnnotationMap(superDecl), annoClass);
173
superDecl = superDecl.getSuperclass();
174
}
175
}
176
177
return result;
178
}
179
180
181
/* Reflectively invoke the values-method of the given annotation
182
* (container), cast it to an array of annotations and return the result.
183
*/
184
@SuppressWarnings("removal")
185
private static <A extends Annotation> A[] getValueArray(Annotation container) {
186
try {
187
// According to JLS the container must have an array-valued value
188
// method. Get the AnnotationType, get the "value" method and invoke
189
// it to get the content.
190
191
Class<? extends Annotation> containerClass = container.annotationType();
192
AnnotationType annoType = AnnotationType.getInstance(containerClass);
193
if (annoType == null)
194
throw invalidContainerException(container, null);
195
Method m = annoType.members().get("value");
196
if (m == null)
197
throw invalidContainerException(container, null);
198
199
if (Proxy.isProxyClass(container.getClass())) {
200
// Invoke by invocation handler
201
InvocationHandler handler = Proxy.getInvocationHandler(container);
202
203
try {
204
// This will erase to (Annotation[]) but we do a runtime cast on the
205
// return-value in the method that call this method.
206
@SuppressWarnings("unchecked")
207
A[] values = (A[]) handler.invoke(container, m, null);
208
return values;
209
} catch (Throwable t) { // from InvocationHandler::invoke
210
throw invalidContainerException(container, t);
211
}
212
} else {
213
// In theory there might be instances of Annotations that are not
214
// implemented using Proxies. Try to invoke the "value" element with
215
// reflection.
216
217
// Declaring class should be an annotation type
218
Class<?> iface = m.getDeclaringClass();
219
if (!iface.isAnnotation())
220
throw new UnsupportedOperationException("Unsupported container annotation type.");
221
// Method must be public
222
if (!Modifier.isPublic(m.getModifiers()))
223
throw new UnsupportedOperationException("Unsupported value member.");
224
225
// Interface might not be public though
226
final Method toInvoke;
227
if (!Modifier.isPublic(iface.getModifiers())) {
228
if (System.getSecurityManager() != null) {
229
toInvoke = AccessController.doPrivileged(new PrivilegedAction<Method>() {
230
@Override
231
public Method run() {
232
Method res = ReflectionFactory.getReflectionFactory().leafCopyMethod(m);
233
res.setAccessible(true);
234
return res;
235
}
236
});
237
} else {
238
toInvoke = ReflectionFactory.getReflectionFactory().leafCopyMethod(m);
239
toInvoke.setAccessible(true);
240
}
241
} else {
242
toInvoke = m;
243
}
244
245
// This will erase to (Annotation[]) but we do a runtime cast on the
246
// return-value in the method that call this method.
247
@SuppressWarnings("unchecked")
248
A[] values = (A[]) toInvoke.invoke(container);
249
250
return values;
251
}
252
} catch (IllegalAccessException | // couldn't loosen security
253
IllegalArgumentException | // parameters doesn't match
254
InvocationTargetException | // the value method threw an exception
255
ClassCastException e) {
256
throw invalidContainerException(container, e);
257
}
258
}
259
260
261
private static AnnotationFormatError invalidContainerException(Annotation anno,
262
Throwable cause) {
263
return new AnnotationFormatError(
264
anno + " is an invalid container for repeating annotations",
265
cause);
266
}
267
268
269
/* Sanity check type of all the annotation instances of type {@code annoClass}
270
* from {@code container}.
271
*/
272
private static <A extends Annotation> void checkTypes(A[] annotations,
273
Annotation container,
274
Class<A> annoClass) {
275
for (A a : annotations) {
276
if (!annoClass.isInstance(a)) {
277
throw new AnnotationFormatError(
278
String.format("%s is an invalid container for " +
279
"repeating annotations of type: %s",
280
container, annoClass));
281
}
282
}
283
}
284
}
285
286