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/AnnotationInvocationHandler.java
41159 views
1
/*
2
* Copyright (c) 2003, 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.io.ObjectInputStream;
29
import java.lang.annotation.*;
30
import java.lang.reflect.*;
31
import java.io.Serializable;
32
import java.util.*;
33
import java.util.stream.*;
34
import java.security.AccessController;
35
import java.security.PrivilegedAction;
36
37
/**
38
* InvocationHandler for dynamic proxy implementation of Annotation.
39
*
40
* @author Josh Bloch
41
* @since 1.5
42
*/
43
class AnnotationInvocationHandler implements InvocationHandler, Serializable {
44
@java.io.Serial
45
private static final long serialVersionUID = 6182022883658399397L;
46
private final Class<? extends Annotation> type;
47
@SuppressWarnings("serial") // Not statically typed as Serializable
48
private final Map<String, Object> memberValues;
49
50
AnnotationInvocationHandler(Class<? extends Annotation> type, Map<String, Object> memberValues) {
51
Class<?>[] superInterfaces = type.getInterfaces();
52
if (!type.isAnnotation() ||
53
superInterfaces.length != 1 ||
54
superInterfaces[0] != java.lang.annotation.Annotation.class)
55
throw new AnnotationFormatError("Attempt to create proxy for a non-annotation type: " +
56
type.getName());
57
this.type = type;
58
this.memberValues = memberValues;
59
}
60
61
public Object invoke(Object proxy, Method method, Object[] args) {
62
String member = method.getName();
63
int parameterCount = method.getParameterCount();
64
65
// Handle Object and Annotation methods
66
if (parameterCount == 1 && member == "equals" &&
67
method.getParameterTypes()[0] == Object.class) {
68
return equalsImpl(proxy, args[0]);
69
}
70
if (parameterCount != 0) {
71
throw new AssertionError("Too many parameters for an annotation method");
72
}
73
74
if (member == "toString") {
75
return toStringImpl();
76
} else if (member == "hashCode") {
77
return hashCodeImpl();
78
} else if (member == "annotationType") {
79
return type;
80
}
81
82
// Handle annotation member accessors
83
Object result = memberValues.get(member);
84
85
if (result == null)
86
throw new IncompleteAnnotationException(type, member);
87
88
if (result instanceof ExceptionProxy)
89
throw ((ExceptionProxy) result).generateException();
90
91
if (result.getClass().isArray() && Array.getLength(result) != 0)
92
result = cloneArray(result);
93
94
return result;
95
}
96
97
/**
98
* This method, which clones its array argument, would not be necessary
99
* if Cloneable had a public clone method.
100
*/
101
private Object cloneArray(Object array) {
102
Class<?> type = array.getClass();
103
104
if (type == byte[].class) {
105
byte[] byteArray = (byte[])array;
106
return byteArray.clone();
107
}
108
if (type == char[].class) {
109
char[] charArray = (char[])array;
110
return charArray.clone();
111
}
112
if (type == double[].class) {
113
double[] doubleArray = (double[])array;
114
return doubleArray.clone();
115
}
116
if (type == float[].class) {
117
float[] floatArray = (float[])array;
118
return floatArray.clone();
119
}
120
if (type == int[].class) {
121
int[] intArray = (int[])array;
122
return intArray.clone();
123
}
124
if (type == long[].class) {
125
long[] longArray = (long[])array;
126
return longArray.clone();
127
}
128
if (type == short[].class) {
129
short[] shortArray = (short[])array;
130
return shortArray.clone();
131
}
132
if (type == boolean[].class) {
133
boolean[] booleanArray = (boolean[])array;
134
return booleanArray.clone();
135
}
136
137
Object[] objectArray = (Object[])array;
138
return objectArray.clone();
139
}
140
141
142
/**
143
* Implementation of dynamicProxy.toString()
144
*/
145
private String toStringImpl() {
146
StringBuilder result = new StringBuilder(128);
147
result.append('@');
148
result.append(type.getName());
149
result.append('(');
150
boolean firstMember = true;
151
Set<Map.Entry<String, Object>> entries = memberValues.entrySet();
152
boolean loneValue = entries.size() == 1;
153
for (Map.Entry<String, Object> e : entries) {
154
if (firstMember)
155
firstMember = false;
156
else
157
result.append(", ");
158
159
String key = e.getKey();
160
if (!loneValue || !"value".equals(key)) {
161
result.append(key);
162
result.append('=');
163
}
164
loneValue = false;
165
result.append(memberValueToString(e.getValue()));
166
}
167
result.append(')');
168
return result.toString();
169
}
170
171
/**
172
* Translates a member value (in "dynamic proxy return form") into a string.
173
*/
174
private static String memberValueToString(Object value) {
175
Class<?> type = value.getClass();
176
if (!type.isArray()) {
177
// primitive value, string, class, enum const, or annotation
178
if (type == Class.class)
179
return toSourceString((Class<?>) value);
180
else if (type == String.class)
181
return toSourceString((String) value);
182
if (type == Character.class)
183
return toSourceString((char) value);
184
else if (type == Double.class)
185
return toSourceString((double) value);
186
else if (type == Float.class)
187
return toSourceString((float) value);
188
else if (type == Long.class)
189
return toSourceString((long) value);
190
else if (type == Byte.class)
191
return toSourceString((byte) value);
192
else
193
return value.toString();
194
} else {
195
Stream<String> stringStream;
196
if (type == byte[].class)
197
stringStream = convert((byte[]) value);
198
else if (type == char[].class)
199
stringStream = convert((char[]) value);
200
else if (type == double[].class)
201
stringStream = DoubleStream.of((double[]) value)
202
.mapToObj(AnnotationInvocationHandler::toSourceString);
203
else if (type == float[].class)
204
stringStream = convert((float[]) value);
205
else if (type == int[].class)
206
stringStream = IntStream.of((int[]) value).mapToObj(String::valueOf);
207
else if (type == long[].class) {
208
stringStream = LongStream.of((long[]) value)
209
.mapToObj(AnnotationInvocationHandler::toSourceString);
210
} else if (type == short[].class)
211
stringStream = convert((short[]) value);
212
else if (type == boolean[].class)
213
stringStream = convert((boolean[]) value);
214
else if (type == Class[].class)
215
stringStream =
216
Arrays.stream((Class<?>[]) value).
217
map(AnnotationInvocationHandler::toSourceString);
218
else if (type == String[].class)
219
stringStream =
220
Arrays.stream((String[])value).
221
map(AnnotationInvocationHandler::toSourceString);
222
else
223
stringStream = Arrays.stream((Object[])value).map(Objects::toString);
224
225
return stringStreamToString(stringStream);
226
}
227
}
228
229
/**
230
* Translates a Class value to a form suitable for use in the
231
* string representation of an annotation.
232
*/
233
private static String toSourceString(Class<?> clazz) {
234
Class<?> finalComponent = clazz;
235
StringBuilder arrayBrackets = new StringBuilder();
236
237
while(finalComponent.isArray()) {
238
finalComponent = finalComponent.getComponentType();
239
arrayBrackets.append("[]");
240
}
241
242
return finalComponent.getName() + arrayBrackets.toString() + ".class";
243
}
244
245
private static String toSourceString(float f) {
246
if (Float.isFinite(f))
247
return Float.toString(f) + "f" ;
248
else {
249
if (Float.isInfinite(f)) {
250
return (f < 0.0f) ? "-1.0f/0.0f": "1.0f/0.0f";
251
} else
252
return "0.0f/0.0f";
253
}
254
}
255
256
private static String toSourceString(double d) {
257
if (Double.isFinite(d))
258
return Double.toString(d);
259
else {
260
if (Double.isInfinite(d)) {
261
return (d < 0.0f) ? "-1.0/0.0": "1.0/0.0";
262
} else
263
return "0.0/0.0";
264
}
265
}
266
267
private static String toSourceString(char c) {
268
StringBuilder sb = new StringBuilder(4);
269
sb.append('\'');
270
sb.append(quote(c));
271
return sb.append('\'') .toString();
272
}
273
274
/**
275
* Escapes a character if it has an escape sequence or is
276
* non-printable ASCII. Leaves non-ASCII characters alone.
277
*/
278
private static String quote(char ch) {
279
switch (ch) {
280
case '\b': return "\\b";
281
case '\f': return "\\f";
282
case '\n': return "\\n";
283
case '\r': return "\\r";
284
case '\t': return "\\t";
285
case '\'': return "\\'";
286
case '\"': return "\\\"";
287
case '\\': return "\\\\";
288
default:
289
return (isPrintableAscii(ch))
290
? String.valueOf(ch)
291
: String.format("\\u%04x", (int) ch);
292
}
293
}
294
295
/**
296
* Is a character printable ASCII?
297
*/
298
private static boolean isPrintableAscii(char ch) {
299
return ch >= ' ' && ch <= '~';
300
}
301
302
private static String toSourceString(byte b) {
303
return String.format("(byte)0x%02x", b);
304
}
305
306
private static String toSourceString(long ell) {
307
return String.valueOf(ell) + "L";
308
}
309
310
/**
311
* Return a string suitable for use in the string representation
312
* of an annotation.
313
*/
314
private static String toSourceString(String s) {
315
StringBuilder sb = new StringBuilder();
316
sb.append('"');
317
for (int i = 0; i < s.length(); i++) {
318
sb.append(quote(s.charAt(i)));
319
}
320
sb.append('"');
321
return sb.toString();
322
}
323
324
private static Stream<String> convert(byte[] values) {
325
List<String> list = new ArrayList<>(values.length);
326
for (byte b : values)
327
list.add(toSourceString(b));
328
return list.stream();
329
}
330
331
private static Stream<String> convert(char[] values) {
332
List<String> list = new ArrayList<>(values.length);
333
for (char c : values)
334
list.add(toSourceString(c));
335
return list.stream();
336
}
337
338
private static Stream<String> convert(float[] values) {
339
List<String> list = new ArrayList<>(values.length);
340
for (float f : values) {
341
list.add(toSourceString(f));
342
}
343
return list.stream();
344
}
345
346
private static Stream<String> convert(short[] values) {
347
List<String> list = new ArrayList<>(values.length);
348
for (short s : values)
349
list.add(Short.toString(s));
350
return list.stream();
351
}
352
353
private static Stream<String> convert(boolean[] values) {
354
List<String> list = new ArrayList<>(values.length);
355
for (boolean b : values)
356
list.add(Boolean.toString(b));
357
return list.stream();
358
}
359
360
private static String stringStreamToString(Stream<String> stream) {
361
return stream.collect(Collectors.joining(", ", "{", "}"));
362
}
363
364
/**
365
* Implementation of dynamicProxy.equals(Object o)
366
*/
367
private Boolean equalsImpl(Object proxy, Object o) {
368
if (o == proxy)
369
return true;
370
371
if (!type.isInstance(o))
372
return false;
373
for (Method memberMethod : getMemberMethods()) {
374
if (memberMethod.isSynthetic())
375
continue;
376
String member = memberMethod.getName();
377
Object ourValue = memberValues.get(member);
378
Object hisValue = null;
379
AnnotationInvocationHandler hisHandler = asOneOfUs(o);
380
if (hisHandler != null) {
381
hisValue = hisHandler.memberValues.get(member);
382
} else {
383
try {
384
hisValue = memberMethod.invoke(o);
385
} catch (InvocationTargetException e) {
386
return false;
387
} catch (IllegalAccessException e) {
388
throw new AssertionError(e);
389
}
390
}
391
if (!memberValueEquals(ourValue, hisValue))
392
return false;
393
}
394
return true;
395
}
396
397
/**
398
* Returns an object's invocation handler if that object is a dynamic
399
* proxy with a handler of type AnnotationInvocationHandler.
400
* Returns null otherwise.
401
*/
402
private AnnotationInvocationHandler asOneOfUs(Object o) {
403
if (Proxy.isProxyClass(o.getClass())) {
404
InvocationHandler handler = Proxy.getInvocationHandler(o);
405
if (handler instanceof AnnotationInvocationHandler)
406
return (AnnotationInvocationHandler) handler;
407
}
408
return null;
409
}
410
411
/**
412
* Returns true iff the two member values in "dynamic proxy return form"
413
* are equal using the appropriate equality function depending on the
414
* member type. The two values will be of the same type unless one of
415
* the containing annotations is ill-formed. If one of the containing
416
* annotations is ill-formed, this method will return false unless the
417
* two members are identical object references.
418
*/
419
private static boolean memberValueEquals(Object v1, Object v2) {
420
Class<?> type = v1.getClass();
421
422
// Check for primitive, string, class, enum const, annotation,
423
// or ExceptionProxy
424
if (!type.isArray())
425
return v1.equals(v2);
426
427
// Check for array of string, class, enum const, annotation,
428
// or ExceptionProxy
429
if (v1 instanceof Object[] && v2 instanceof Object[])
430
return Arrays.equals((Object[]) v1, (Object[]) v2);
431
432
// Check for ill formed annotation(s)
433
if (v2.getClass() != type)
434
return false;
435
436
// Deal with array of primitives
437
if (type == byte[].class)
438
return Arrays.equals((byte[]) v1, (byte[]) v2);
439
if (type == char[].class)
440
return Arrays.equals((char[]) v1, (char[]) v2);
441
if (type == double[].class)
442
return Arrays.equals((double[]) v1, (double[]) v2);
443
if (type == float[].class)
444
return Arrays.equals((float[]) v1, (float[]) v2);
445
if (type == int[].class)
446
return Arrays.equals((int[]) v1, (int[]) v2);
447
if (type == long[].class)
448
return Arrays.equals((long[]) v1, (long[]) v2);
449
if (type == short[].class)
450
return Arrays.equals((short[]) v1, (short[]) v2);
451
assert type == boolean[].class;
452
return Arrays.equals((boolean[]) v1, (boolean[]) v2);
453
}
454
455
/**
456
* Returns the member methods for our annotation type. These are
457
* obtained lazily and cached, as they're expensive to obtain
458
* and we only need them if our equals method is invoked (which should
459
* be rare).
460
*/
461
private Method[] getMemberMethods() {
462
Method[] value = memberMethods;
463
if (value == null) {
464
value = computeMemberMethods();
465
memberMethods = value;
466
}
467
return value;
468
}
469
470
@SuppressWarnings("removal")
471
private Method[] computeMemberMethods() {
472
return AccessController.doPrivileged(
473
new PrivilegedAction<Method[]>() {
474
public Method[] run() {
475
final Method[] methods = type.getDeclaredMethods();
476
validateAnnotationMethods(methods);
477
AccessibleObject.setAccessible(methods, true);
478
return methods;
479
}});
480
}
481
482
private transient volatile Method[] memberMethods;
483
484
/**
485
* Validates that a method is structurally appropriate for an
486
* annotation type. As of Java SE 8, annotation types cannot
487
* contain static methods and the declared methods of an
488
* annotation type must take zero arguments and there are
489
* restrictions on the return type.
490
*/
491
private void validateAnnotationMethods(Method[] memberMethods) {
492
/*
493
* Specification citations below are from JLS
494
* 9.6.1. Annotation Type Elements
495
*/
496
boolean valid = true;
497
Method currentMethod = null;
498
for(Method method : memberMethods) {
499
currentMethod = method;
500
int modifiers = method.getModifiers();
501
// Skip over methods that may be a static initializer or
502
// similar construct. A static initializer may be used for
503
// purposes such as initializing a lambda stored in an
504
// interface field.
505
if (method.isSynthetic() &&
506
(modifiers & (Modifier.STATIC | Modifier.PRIVATE)) != 0 &&
507
method.getParameterCount() == 0) {
508
continue;
509
}
510
511
/*
512
* "By virtue of the AnnotationTypeElementDeclaration
513
* production, a method declaration in an annotation type
514
* declaration cannot have formal parameters, type
515
* parameters, or a throws clause.
516
*
517
* "By virtue of the AnnotationTypeElementModifier
518
* production, a method declaration in an annotation type
519
* declaration cannot be default or static."
520
*/
521
if (modifiers != (Modifier.PUBLIC | Modifier.ABSTRACT) ||
522
method.isDefault() ||
523
method.getParameterCount() != 0 ||
524
method.getExceptionTypes().length != 0) {
525
valid = false;
526
break;
527
}
528
529
/*
530
* "It is a compile-time error if the return type of a
531
* method declared in an annotation type is not one of the
532
* following: a primitive type, String, Class, any
533
* parameterized invocation of Class, an enum type
534
* (section 8.9), an annotation type, or an array type
535
* (chapter 10) whose element type is one of the preceding
536
* types."
537
*/
538
Class<?> returnType = method.getReturnType();
539
if (returnType.isArray()) {
540
returnType = returnType.getComponentType();
541
if (returnType.isArray()) { // Only single dimensional arrays
542
valid = false;
543
break;
544
}
545
}
546
547
if (!((returnType.isPrimitive() && returnType != void.class) ||
548
returnType == java.lang.String.class ||
549
returnType == java.lang.Class.class ||
550
returnType.isEnum() ||
551
returnType.isAnnotation())) {
552
valid = false;
553
break;
554
}
555
556
/*
557
* "It is a compile-time error if any method declared in an
558
* annotation type has a signature that is
559
* override-equivalent to that of any public or protected
560
* method declared in class Object or in the interface
561
* java.lang.annotation.Annotation."
562
*
563
* The methods in Object or Annotation meeting the other
564
* criteria (no arguments, contrained return type, etc.)
565
* above are:
566
*
567
* String toString()
568
* int hashCode()
569
* Class<? extends Annotation> annotationType()
570
*/
571
String methodName = method.getName();
572
if ((methodName.equals("toString") && returnType == java.lang.String.class) ||
573
(methodName.equals("hashCode") && returnType == int.class) ||
574
(methodName.equals("annotationType") && returnType == java.lang.Class.class)) {
575
valid = false;
576
break;
577
}
578
}
579
if (valid)
580
return;
581
else
582
throw new AnnotationFormatError("Malformed method on an annotation type: " +
583
currentMethod.toString());
584
}
585
586
/**
587
* Implementation of dynamicProxy.hashCode()
588
*/
589
private int hashCodeImpl() {
590
int result = 0;
591
for (Map.Entry<String, Object> e : memberValues.entrySet()) {
592
result += (127 * e.getKey().hashCode()) ^
593
memberValueHashCode(e.getValue());
594
}
595
return result;
596
}
597
598
/**
599
* Computes hashCode of a member value (in "dynamic proxy return form")
600
*/
601
private static int memberValueHashCode(Object value) {
602
Class<?> type = value.getClass();
603
if (!type.isArray()) // primitive, string, class, enum const,
604
// or annotation
605
return value.hashCode();
606
607
if (type == byte[].class)
608
return Arrays.hashCode((byte[]) value);
609
if (type == char[].class)
610
return Arrays.hashCode((char[]) value);
611
if (type == double[].class)
612
return Arrays.hashCode((double[]) value);
613
if (type == float[].class)
614
return Arrays.hashCode((float[]) value);
615
if (type == int[].class)
616
return Arrays.hashCode((int[]) value);
617
if (type == long[].class)
618
return Arrays.hashCode((long[]) value);
619
if (type == short[].class)
620
return Arrays.hashCode((short[]) value);
621
if (type == boolean[].class)
622
return Arrays.hashCode((boolean[]) value);
623
return Arrays.hashCode((Object[]) value);
624
}
625
626
@java.io.Serial
627
private void readObject(java.io.ObjectInputStream s)
628
throws java.io.IOException, ClassNotFoundException {
629
ObjectInputStream.GetField fields = s.readFields();
630
631
@SuppressWarnings("unchecked")
632
Class<? extends Annotation> t = (Class<? extends Annotation>)fields.get("type", null);
633
@SuppressWarnings("unchecked")
634
Map<String, Object> streamVals = (Map<String, Object>)fields.get("memberValues", null);
635
636
// Check to make sure that types have not evolved incompatibly
637
638
AnnotationType annotationType = null;
639
try {
640
annotationType = AnnotationType.getInstance(t);
641
} catch(IllegalArgumentException e) {
642
// Class is no longer an annotation type; time to punch out
643
throw new java.io.InvalidObjectException("Non-annotation type in annotation serial stream");
644
}
645
646
Map<String, Class<?>> memberTypes = annotationType.memberTypes();
647
// consistent with runtime Map type
648
Map<String, Object> mv = new LinkedHashMap<>();
649
650
// If there are annotation members without values, that
651
// situation is handled by the invoke method.
652
for (Map.Entry<String, Object> memberValue : streamVals.entrySet()) {
653
String name = memberValue.getKey();
654
Object value = null;
655
Class<?> memberType = memberTypes.get(name);
656
if (memberType != null) { // i.e. member still exists
657
value = memberValue.getValue();
658
if (!(memberType.isInstance(value) ||
659
value instanceof ExceptionProxy)) {
660
value = new AnnotationTypeMismatchExceptionProxy(
661
value.getClass() + "[" + value + "]").setMember(
662
annotationType.members().get(name));
663
}
664
}
665
mv.put(name, value);
666
}
667
668
UnsafeAccessor.setType(this, t);
669
UnsafeAccessor.setMemberValues(this, mv);
670
}
671
672
private static class UnsafeAccessor {
673
private static final jdk.internal.misc.Unsafe unsafe
674
= jdk.internal.misc.Unsafe.getUnsafe();
675
private static final long typeOffset = unsafe.objectFieldOffset
676
(AnnotationInvocationHandler.class, "type");
677
private static final long memberValuesOffset = unsafe.objectFieldOffset
678
(AnnotationInvocationHandler.class, "memberValues");
679
680
static void setType(AnnotationInvocationHandler o,
681
Class<? extends Annotation> type) {
682
unsafe.putReference(o, typeOffset, type);
683
}
684
685
static void setMemberValues(AnnotationInvocationHandler o,
686
Map<String, Object> memberValues) {
687
unsafe.putReference(o, memberValuesOffset, memberValues);
688
}
689
}
690
}
691
692