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/AnnotationParser.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.lang.annotation.*;
29
import java.lang.reflect.*;
30
import java.nio.BufferUnderflowException;
31
import java.nio.ByteBuffer;
32
import java.util.*;
33
import java.util.function.Supplier;
34
import java.security.AccessController;
35
import java.security.PrivilegedAction;
36
import jdk.internal.reflect.ConstantPool;
37
38
import sun.reflect.generics.parser.SignatureParser;
39
import sun.reflect.generics.tree.TypeSignature;
40
import sun.reflect.generics.factory.GenericsFactory;
41
import sun.reflect.generics.factory.CoreReflectionFactory;
42
import sun.reflect.generics.visitor.Reifier;
43
import sun.reflect.generics.scope.ClassScope;
44
45
/**
46
* Parser for Java programming language annotations. Translates
47
* annotation byte streams emitted by compiler into annotation objects.
48
*
49
* @author Josh Bloch
50
* @since 1.5
51
*/
52
public class AnnotationParser {
53
/**
54
* Parses the annotations described by the specified byte array.
55
* resolving constant references in the specified constant pool.
56
* The array must contain an array of annotations as described
57
* in the RuntimeVisibleAnnotations_attribute:
58
*
59
* u2 num_annotations;
60
* annotation annotations[num_annotations];
61
*
62
* @throws AnnotationFormatError if an annotation is found to be
63
* malformed.
64
*/
65
public static Map<Class<? extends Annotation>, Annotation> parseAnnotations(
66
byte[] rawAnnotations,
67
ConstantPool constPool,
68
Class<?> container) {
69
if (rawAnnotations == null)
70
return Collections.emptyMap();
71
72
try {
73
return parseAnnotations2(rawAnnotations, constPool, container, null);
74
} catch(BufferUnderflowException e) {
75
throw new AnnotationFormatError("Unexpected end of annotations.");
76
} catch(IllegalArgumentException e) {
77
// Type mismatch in constant pool
78
throw new AnnotationFormatError(e);
79
}
80
}
81
82
/**
83
* Like {@link #parseAnnotations(byte[], sun.reflect.ConstantPool, Class)}
84
* with an additional parameter {@code selectAnnotationClasses} which selects the
85
* annotation types to parse (other than selected are quickly skipped).<p>
86
* This method is only used to parse select meta annotations in the construction
87
* phase of {@link AnnotationType} instances to prevent infinite recursion.
88
*
89
* @param selectAnnotationClasses an array of annotation types to select when parsing
90
*/
91
@SafeVarargs
92
@SuppressWarnings("varargs") // selectAnnotationClasses is used safely
93
static Map<Class<? extends Annotation>, Annotation> parseSelectAnnotations(
94
byte[] rawAnnotations,
95
ConstantPool constPool,
96
Class<?> container,
97
Class<? extends Annotation> ... selectAnnotationClasses) {
98
if (rawAnnotations == null)
99
return Collections.emptyMap();
100
101
try {
102
return parseAnnotations2(rawAnnotations, constPool, container, selectAnnotationClasses);
103
} catch(BufferUnderflowException e) {
104
throw new AnnotationFormatError("Unexpected end of annotations.");
105
} catch(IllegalArgumentException e) {
106
// Type mismatch in constant pool
107
throw new AnnotationFormatError(e);
108
}
109
}
110
111
private static Map<Class<? extends Annotation>, Annotation> parseAnnotations2(
112
byte[] rawAnnotations,
113
ConstantPool constPool,
114
Class<?> container,
115
Class<? extends Annotation>[] selectAnnotationClasses) {
116
Map<Class<? extends Annotation>, Annotation> result =
117
new LinkedHashMap<Class<? extends Annotation>, Annotation>();
118
ByteBuffer buf = ByteBuffer.wrap(rawAnnotations);
119
int numAnnotations = buf.getShort() & 0xFFFF;
120
for (int i = 0; i < numAnnotations; i++) {
121
Annotation a = parseAnnotation2(buf, constPool, container, false, selectAnnotationClasses);
122
if (a != null) {
123
Class<? extends Annotation> klass = a.annotationType();
124
if (AnnotationType.getInstance(klass).retention() == RetentionPolicy.RUNTIME &&
125
result.put(klass, a) != null) {
126
throw new AnnotationFormatError(
127
"Duplicate annotation for class: "+klass+": " + a);
128
}
129
}
130
}
131
return result;
132
}
133
134
/**
135
* Parses the parameter annotations described by the specified byte array.
136
* resolving constant references in the specified constant pool.
137
* The array must contain an array of annotations as described
138
* in the RuntimeVisibleParameterAnnotations_attribute:
139
*
140
* u1 num_parameters;
141
* {
142
* u2 num_annotations;
143
* annotation annotations[num_annotations];
144
* } parameter_annotations[num_parameters];
145
*
146
* Unlike parseAnnotations, rawAnnotations must not be null!
147
* A null value must be handled by the caller. This is so because
148
* we cannot determine the number of parameters if rawAnnotations
149
* is null. Also, the caller should check that the number
150
* of parameters indicated by the return value of this method
151
* matches the actual number of method parameters. A mismatch
152
* indicates that an AnnotationFormatError should be thrown.
153
*
154
* @throws AnnotationFormatError if an annotation is found to be
155
* malformed.
156
*/
157
public static Annotation[][] parseParameterAnnotations(
158
byte[] rawAnnotations,
159
ConstantPool constPool,
160
Class<?> container) {
161
try {
162
return parseParameterAnnotations2(rawAnnotations, constPool, container);
163
} catch(BufferUnderflowException e) {
164
throw new AnnotationFormatError(
165
"Unexpected end of parameter annotations.");
166
} catch(IllegalArgumentException e) {
167
// Type mismatch in constant pool
168
throw new AnnotationFormatError(e);
169
}
170
}
171
172
private static Annotation[][] parseParameterAnnotations2(
173
byte[] rawAnnotations,
174
ConstantPool constPool,
175
Class<?> container) {
176
ByteBuffer buf = ByteBuffer.wrap(rawAnnotations);
177
int numParameters = buf.get() & 0xFF;
178
Annotation[][] result = new Annotation[numParameters][];
179
180
for (int i = 0; i < numParameters; i++) {
181
int numAnnotations = buf.getShort() & 0xFFFF;
182
List<Annotation> annotations =
183
new ArrayList<Annotation>(numAnnotations);
184
for (int j = 0; j < numAnnotations; j++) {
185
Annotation a = parseAnnotation(buf, constPool, container, false);
186
if (a != null) {
187
AnnotationType type = AnnotationType.getInstance(
188
a.annotationType());
189
if (type.retention() == RetentionPolicy.RUNTIME)
190
annotations.add(a);
191
}
192
}
193
result[i] = annotations.toArray(EMPTY_ANNOTATIONS_ARRAY);
194
}
195
return result;
196
}
197
198
private static final Annotation[] EMPTY_ANNOTATIONS_ARRAY =
199
new Annotation[0];
200
201
/**
202
* Parses the annotation at the current position in the specified
203
* byte buffer, resolving constant references in the specified constant
204
* pool. The cursor of the byte buffer must point to an "annotation
205
* structure" as described in the RuntimeVisibleAnnotations_attribute:
206
*
207
* annotation {
208
* u2 type_index;
209
* u2 num_member_value_pairs;
210
* { u2 member_name_index;
211
* member_value value;
212
* } member_value_pairs[num_member_value_pairs];
213
* }
214
* }
215
*
216
* Returns the annotation, or null if the annotation's type cannot
217
* be found by the VM, or is not a valid annotation type.
218
*
219
* @param exceptionOnMissingAnnotationClass if true, throw
220
* TypeNotPresentException if a referenced annotation type is not
221
* available at runtime
222
*/
223
static Annotation parseAnnotation(ByteBuffer buf,
224
ConstantPool constPool,
225
Class<?> container,
226
boolean exceptionOnMissingAnnotationClass) {
227
return parseAnnotation2(buf, constPool, container, exceptionOnMissingAnnotationClass, null);
228
}
229
230
@SuppressWarnings("unchecked")
231
private static Annotation parseAnnotation2(ByteBuffer buf,
232
ConstantPool constPool,
233
Class<?> container,
234
boolean exceptionOnMissingAnnotationClass,
235
Class<? extends Annotation>[] selectAnnotationClasses) {
236
int typeIndex = buf.getShort() & 0xFFFF;
237
Class<? extends Annotation> annotationClass = null;
238
String sig = "[unknown]";
239
try {
240
sig = constPool.getUTF8At(typeIndex);
241
annotationClass = (Class<? extends Annotation>)parseSig(sig, container);
242
} catch (NoClassDefFoundError e) {
243
if (exceptionOnMissingAnnotationClass)
244
// note: at this point sig is "[unknown]" or VM-style
245
// name instead of a binary name
246
throw new TypeNotPresentException(sig, e);
247
skipAnnotation(buf, false);
248
return null;
249
}
250
catch (TypeNotPresentException e) {
251
if (exceptionOnMissingAnnotationClass)
252
throw e;
253
skipAnnotation(buf, false);
254
return null;
255
}
256
if (selectAnnotationClasses != null && !contains(selectAnnotationClasses, annotationClass)) {
257
skipAnnotation(buf, false);
258
return null;
259
}
260
AnnotationType type = null;
261
try {
262
type = AnnotationType.getInstance(annotationClass);
263
} catch (IllegalArgumentException e) {
264
skipAnnotation(buf, false);
265
return null;
266
}
267
268
Map<String, Class<?>> memberTypes = type.memberTypes();
269
Map<String, Object> memberValues =
270
new LinkedHashMap<String, Object>(type.memberDefaults());
271
272
int numMembers = buf.getShort() & 0xFFFF;
273
for (int i = 0; i < numMembers; i++) {
274
int memberNameIndex = buf.getShort() & 0xFFFF;
275
String memberName = constPool.getUTF8At(memberNameIndex);
276
Class<?> memberType = memberTypes.get(memberName);
277
278
if (memberType == null) {
279
// Member is no longer present in annotation type; ignore it
280
skipMemberValue(buf);
281
} else {
282
Object value = parseMemberValue(memberType, buf, constPool, container);
283
if (value instanceof AnnotationTypeMismatchExceptionProxy)
284
((AnnotationTypeMismatchExceptionProxy) value).
285
setMember(type.members().get(memberName));
286
memberValues.put(memberName, value);
287
}
288
}
289
return annotationForMap(annotationClass, memberValues);
290
}
291
292
/**
293
* Returns an annotation of the given type backed by the given
294
* member {@literal ->} value map.
295
*/
296
@SuppressWarnings("removal")
297
public static Annotation annotationForMap(final Class<? extends Annotation> type,
298
final Map<String, Object> memberValues)
299
{
300
return AccessController.doPrivileged(new PrivilegedAction<Annotation>() {
301
public Annotation run() {
302
return (Annotation) Proxy.newProxyInstance(
303
type.getClassLoader(), new Class<?>[] { type },
304
new AnnotationInvocationHandler(type, memberValues));
305
}});
306
}
307
308
/**
309
* Parses the annotation member value at the current position in the
310
* specified byte buffer, resolving constant references in the specified
311
* constant pool. The cursor of the byte buffer must point to a
312
* "member_value structure" as described in the
313
* RuntimeVisibleAnnotations_attribute:
314
*
315
* member_value {
316
* u1 tag;
317
* union {
318
* u2 const_value_index;
319
* {
320
* u2 type_name_index;
321
* u2 const_name_index;
322
* } enum_const_value;
323
* u2 class_info_index;
324
* annotation annotation_value;
325
* {
326
* u2 num_values;
327
* member_value values[num_values];
328
* } array_value;
329
* } value;
330
* }
331
*
332
* The member must be of the indicated type. If it is not, this
333
* method returns an AnnotationTypeMismatchExceptionProxy.
334
*/
335
@SuppressWarnings("unchecked")
336
public static Object parseMemberValue(Class<?> memberType,
337
ByteBuffer buf,
338
ConstantPool constPool,
339
Class<?> container) {
340
Object result = null;
341
int tag = buf.get();
342
switch(tag) {
343
case 'e':
344
return parseEnumValue((Class<? extends Enum<?>>)memberType, buf, constPool, container);
345
case 'c':
346
result = parseClassValue(buf, constPool, container);
347
break;
348
case '@':
349
result = parseAnnotation(buf, constPool, container, true);
350
break;
351
case '[':
352
return parseArray(memberType, buf, constPool, container);
353
default:
354
result = parseConst(tag, buf, constPool);
355
}
356
357
if (result == null) {
358
result = new AnnotationTypeMismatchExceptionProxy(
359
memberType.getClass().getName());
360
} else if (!(result instanceof ExceptionProxy) &&
361
!memberType.isInstance(result)) {
362
result = new AnnotationTypeMismatchExceptionProxy(
363
result.getClass() + "[" + result + "]");
364
}
365
return result;
366
}
367
368
/**
369
* Parses the primitive or String annotation member value indicated by
370
* the specified tag byte at the current position in the specified byte
371
* buffer, resolving constant reference in the specified constant pool.
372
* The cursor of the byte buffer must point to an annotation member value
373
* of the type indicated by the specified tag, as described in the
374
* RuntimeVisibleAnnotations_attribute:
375
*
376
* u2 const_value_index;
377
*/
378
private static Object parseConst(int tag,
379
ByteBuffer buf, ConstantPool constPool) {
380
int constIndex = buf.getShort() & 0xFFFF;
381
switch(tag) {
382
case 'B':
383
return Byte.valueOf((byte) constPool.getIntAt(constIndex));
384
case 'C':
385
return Character.valueOf((char) constPool.getIntAt(constIndex));
386
case 'D':
387
return Double.valueOf(constPool.getDoubleAt(constIndex));
388
case 'F':
389
return Float.valueOf(constPool.getFloatAt(constIndex));
390
case 'I':
391
return Integer.valueOf(constPool.getIntAt(constIndex));
392
case 'J':
393
return Long.valueOf(constPool.getLongAt(constIndex));
394
case 'S':
395
return Short.valueOf((short) constPool.getIntAt(constIndex));
396
case 'Z':
397
return Boolean.valueOf(constPool.getIntAt(constIndex) != 0);
398
case 's':
399
return constPool.getUTF8At(constIndex);
400
default:
401
throw new AnnotationFormatError(
402
"Invalid member-value tag in annotation: " + tag);
403
}
404
}
405
406
/**
407
* Parses the Class member value at the current position in the
408
* specified byte buffer, resolving constant references in the specified
409
* constant pool. The cursor of the byte buffer must point to a "class
410
* info index" as described in the RuntimeVisibleAnnotations_attribute:
411
*
412
* u2 class_info_index;
413
*/
414
private static Object parseClassValue(ByteBuffer buf,
415
ConstantPool constPool,
416
Class<?> container) {
417
int classIndex = buf.getShort() & 0xFFFF;
418
try {
419
String sig = constPool.getUTF8At(classIndex);
420
return parseSig(sig, container);
421
} catch (NoClassDefFoundError e) {
422
return new TypeNotPresentExceptionProxy("[unknown]", e);
423
} catch (TypeNotPresentException e) {
424
return new TypeNotPresentExceptionProxy(e.typeName(), e.getCause());
425
}
426
}
427
428
private static Class<?> parseSig(String sig, Class<?> container) {
429
if (sig.equals("V")) return void.class;
430
SignatureParser parser = SignatureParser.make();
431
TypeSignature typeSig = parser.parseTypeSig(sig);
432
GenericsFactory factory = CoreReflectionFactory.make(container, ClassScope.make(container));
433
Reifier reify = Reifier.make(factory);
434
typeSig.accept(reify);
435
Type result = reify.getResult();
436
return toClass(result);
437
}
438
static Class<?> toClass(Type o) {
439
if (o instanceof GenericArrayType)
440
return Array.newInstance(toClass(((GenericArrayType)o).getGenericComponentType()),
441
0)
442
.getClass();
443
return (Class)o;
444
}
445
446
/**
447
* Parses the enum constant member value at the current position in the
448
* specified byte buffer, resolving constant references in the specified
449
* constant pool. The cursor of the byte buffer must point to a
450
* "enum_const_value structure" as described in the
451
* RuntimeVisibleAnnotations_attribute:
452
*
453
* {
454
* u2 type_name_index;
455
* u2 const_name_index;
456
* } enum_const_value;
457
*/
458
@SuppressWarnings({"rawtypes", "unchecked"})
459
private static Object parseEnumValue(Class<? extends Enum> enumType, ByteBuffer buf,
460
ConstantPool constPool,
461
Class<?> container) {
462
int typeNameIndex = buf.getShort() & 0xFFFF;
463
String typeName = constPool.getUTF8At(typeNameIndex);
464
int constNameIndex = buf.getShort() & 0xFFFF;
465
String constName = constPool.getUTF8At(constNameIndex);
466
if (!enumType.isEnum()) {
467
return new AnnotationTypeMismatchExceptionProxy(
468
typeName + "." + constName);
469
} else if (enumType != parseSig(typeName, container)) {
470
return new AnnotationTypeMismatchExceptionProxy(
471
typeName + "." + constName);
472
}
473
474
try {
475
return Enum.valueOf(enumType, constName);
476
} catch(IllegalArgumentException e) {
477
return new EnumConstantNotPresentExceptionProxy(
478
(Class<? extends Enum<?>>)enumType, constName);
479
}
480
}
481
482
/**
483
* Parses the array value at the current position in the specified byte
484
* buffer, resolving constant references in the specified constant pool.
485
* The cursor of the byte buffer must point to an array value struct
486
* as specified in the RuntimeVisibleAnnotations_attribute:
487
*
488
* {
489
* u2 num_values;
490
* member_value values[num_values];
491
* } array_value;
492
*
493
* If the array values do not match arrayType, an
494
* AnnotationTypeMismatchExceptionProxy will be returned.
495
*/
496
@SuppressWarnings("unchecked")
497
private static Object parseArray(Class<?> arrayType,
498
ByteBuffer buf,
499
ConstantPool constPool,
500
Class<?> container) {
501
int length = buf.getShort() & 0xFFFF; // Number of array components
502
Class<?> componentType = arrayType.getComponentType();
503
504
if (componentType == byte.class) {
505
return parseByteArray(length, buf, constPool);
506
} else if (componentType == char.class) {
507
return parseCharArray(length, buf, constPool);
508
} else if (componentType == double.class) {
509
return parseDoubleArray(length, buf, constPool);
510
} else if (componentType == float.class) {
511
return parseFloatArray(length, buf, constPool);
512
} else if (componentType == int.class) {
513
return parseIntArray(length, buf, constPool);
514
} else if (componentType == long.class) {
515
return parseLongArray(length, buf, constPool);
516
} else if (componentType == short.class) {
517
return parseShortArray(length, buf, constPool);
518
} else if (componentType == boolean.class) {
519
return parseBooleanArray(length, buf, constPool);
520
} else if (componentType == String.class) {
521
return parseStringArray(length, buf, constPool);
522
} else if (componentType == Class.class) {
523
return parseClassArray(length, buf, constPool, container);
524
} else if (componentType.isEnum()) {
525
return parseEnumArray(length, (Class<? extends Enum<?>>)componentType, buf,
526
constPool, container);
527
} else {
528
assert componentType.isAnnotation();
529
return parseAnnotationArray(length, (Class <? extends Annotation>)componentType, buf,
530
constPool, container);
531
}
532
}
533
534
private static Object parseByteArray(int length,
535
ByteBuffer buf, ConstantPool constPool) {
536
byte[] result = new byte[length];
537
boolean typeMismatch = false;
538
int tag = 0;
539
540
for (int i = 0; i < length; i++) {
541
tag = buf.get();
542
if (tag == 'B') {
543
int index = buf.getShort() & 0xFFFF;
544
result[i] = (byte) constPool.getIntAt(index);
545
} else {
546
skipMemberValue(tag, buf);
547
typeMismatch = true;
548
}
549
}
550
return typeMismatch ? exceptionProxy(tag) : result;
551
}
552
553
private static Object parseCharArray(int length,
554
ByteBuffer buf, ConstantPool constPool) {
555
char[] result = new char[length];
556
boolean typeMismatch = false;
557
byte tag = 0;
558
559
for (int i = 0; i < length; i++) {
560
tag = buf.get();
561
if (tag == 'C') {
562
int index = buf.getShort() & 0xFFFF;
563
result[i] = (char) constPool.getIntAt(index);
564
} else {
565
skipMemberValue(tag, buf);
566
typeMismatch = true;
567
}
568
}
569
return typeMismatch ? exceptionProxy(tag) : result;
570
}
571
572
private static Object parseDoubleArray(int length,
573
ByteBuffer buf, ConstantPool constPool) {
574
double[] result = new double[length];
575
boolean typeMismatch = false;
576
int tag = 0;
577
578
for (int i = 0; i < length; i++) {
579
tag = buf.get();
580
if (tag == 'D') {
581
int index = buf.getShort() & 0xFFFF;
582
result[i] = constPool.getDoubleAt(index);
583
} else {
584
skipMemberValue(tag, buf);
585
typeMismatch = true;
586
}
587
}
588
return typeMismatch ? exceptionProxy(tag) : result;
589
}
590
591
private static Object parseFloatArray(int length,
592
ByteBuffer buf, ConstantPool constPool) {
593
float[] result = new float[length];
594
boolean typeMismatch = false;
595
int tag = 0;
596
597
for (int i = 0; i < length; i++) {
598
tag = buf.get();
599
if (tag == 'F') {
600
int index = buf.getShort() & 0xFFFF;
601
result[i] = constPool.getFloatAt(index);
602
} else {
603
skipMemberValue(tag, buf);
604
typeMismatch = true;
605
}
606
}
607
return typeMismatch ? exceptionProxy(tag) : result;
608
}
609
610
private static Object parseIntArray(int length,
611
ByteBuffer buf, ConstantPool constPool) {
612
int[] result = new int[length];
613
boolean typeMismatch = false;
614
int tag = 0;
615
616
for (int i = 0; i < length; i++) {
617
tag = buf.get();
618
if (tag == 'I') {
619
int index = buf.getShort() & 0xFFFF;
620
result[i] = constPool.getIntAt(index);
621
} else {
622
skipMemberValue(tag, buf);
623
typeMismatch = true;
624
}
625
}
626
return typeMismatch ? exceptionProxy(tag) : result;
627
}
628
629
private static Object parseLongArray(int length,
630
ByteBuffer buf, ConstantPool constPool) {
631
long[] result = new long[length];
632
boolean typeMismatch = false;
633
int tag = 0;
634
635
for (int i = 0; i < length; i++) {
636
tag = buf.get();
637
if (tag == 'J') {
638
int index = buf.getShort() & 0xFFFF;
639
result[i] = constPool.getLongAt(index);
640
} else {
641
skipMemberValue(tag, buf);
642
typeMismatch = true;
643
}
644
}
645
return typeMismatch ? exceptionProxy(tag) : result;
646
}
647
648
private static Object parseShortArray(int length,
649
ByteBuffer buf, ConstantPool constPool) {
650
short[] result = new short[length];
651
boolean typeMismatch = false;
652
int tag = 0;
653
654
for (int i = 0; i < length; i++) {
655
tag = buf.get();
656
if (tag == 'S') {
657
int index = buf.getShort() & 0xFFFF;
658
result[i] = (short) constPool.getIntAt(index);
659
} else {
660
skipMemberValue(tag, buf);
661
typeMismatch = true;
662
}
663
}
664
return typeMismatch ? exceptionProxy(tag) : result;
665
}
666
667
private static Object parseBooleanArray(int length,
668
ByteBuffer buf, ConstantPool constPool) {
669
boolean[] result = new boolean[length];
670
boolean typeMismatch = false;
671
int tag = 0;
672
673
for (int i = 0; i < length; i++) {
674
tag = buf.get();
675
if (tag == 'Z') {
676
int index = buf.getShort() & 0xFFFF;
677
result[i] = (constPool.getIntAt(index) != 0);
678
} else {
679
skipMemberValue(tag, buf);
680
typeMismatch = true;
681
}
682
}
683
return typeMismatch ? exceptionProxy(tag) : result;
684
}
685
686
private static Object parseStringArray(int length,
687
ByteBuffer buf, ConstantPool constPool) {
688
String[] result = new String[length];
689
boolean typeMismatch = false;
690
int tag = 0;
691
692
for (int i = 0; i < length; i++) {
693
tag = buf.get();
694
if (tag == 's') {
695
int index = buf.getShort() & 0xFFFF;
696
result[i] = constPool.getUTF8At(index);
697
} else {
698
skipMemberValue(tag, buf);
699
typeMismatch = true;
700
}
701
}
702
return typeMismatch ? exceptionProxy(tag) : result;
703
}
704
705
private static Object parseClassArray(int length,
706
ByteBuffer buf,
707
ConstantPool constPool,
708
Class<?> container) {
709
return parseArrayElements(new Class<?>[length],
710
buf, 'c', () -> parseClassValue(buf, constPool, container));
711
}
712
713
private static Object parseEnumArray(int length, Class<? extends Enum<?>> enumType,
714
ByteBuffer buf,
715
ConstantPool constPool,
716
Class<?> container) {
717
return parseArrayElements((Object[]) Array.newInstance(enumType, length),
718
buf, 'e', () -> parseEnumValue(enumType, buf, constPool, container));
719
}
720
721
private static Object parseAnnotationArray(int length,
722
Class<? extends Annotation> annotationType,
723
ByteBuffer buf,
724
ConstantPool constPool,
725
Class<?> container) {
726
return parseArrayElements((Object[]) Array.newInstance(annotationType, length),
727
buf, '@', () -> parseAnnotation(buf, constPool, container, true));
728
}
729
730
private static Object parseArrayElements(Object[] result,
731
ByteBuffer buf,
732
int expectedTag,
733
Supplier<Object> parseElement) {
734
Object exceptionProxy = null;
735
for (int i = 0; i < result.length; i++) {
736
int tag = buf.get();
737
if (tag == expectedTag) {
738
Object value = parseElement.get();
739
if (value instanceof ExceptionProxy) {
740
if (exceptionProxy == null) exceptionProxy = (ExceptionProxy) value;
741
} else {
742
result[i] = value;
743
}
744
} else {
745
skipMemberValue(tag, buf);
746
if (exceptionProxy == null) exceptionProxy = exceptionProxy(tag);
747
}
748
}
749
return (exceptionProxy != null) ? exceptionProxy : result;
750
}
751
752
/**
753
* Returns an appropriate exception proxy for a mismatching array
754
* annotation where the erroneous array has the specified tag.
755
*/
756
private static ExceptionProxy exceptionProxy(int tag) {
757
return new AnnotationTypeMismatchExceptionProxy(
758
"Array with component tag: " + tag);
759
}
760
761
/**
762
* Skips the annotation at the current position in the specified
763
* byte buffer. The cursor of the byte buffer must point to
764
* an "annotation structure" OR two bytes into an annotation
765
* structure (i.e., after the type index).
766
*
767
* @param complete true if the byte buffer points to the beginning
768
* of an annotation structure (rather than two bytes in).
769
*/
770
private static void skipAnnotation(ByteBuffer buf, boolean complete) {
771
if (complete)
772
buf.getShort(); // Skip type index
773
int numMembers = buf.getShort() & 0xFFFF;
774
for (int i = 0; i < numMembers; i++) {
775
buf.getShort(); // Skip memberNameIndex
776
skipMemberValue(buf);
777
}
778
}
779
780
/**
781
* Skips the annotation member value at the current position in the
782
* specified byte buffer. The cursor of the byte buffer must point to a
783
* "member_value structure."
784
*/
785
private static void skipMemberValue(ByteBuffer buf) {
786
int tag = buf.get();
787
skipMemberValue(tag, buf);
788
}
789
790
/**
791
* Skips the annotation member value at the current position in the
792
* specified byte buffer. The cursor of the byte buffer must point
793
* immediately after the tag in a "member_value structure."
794
*/
795
private static void skipMemberValue(int tag, ByteBuffer buf) {
796
switch(tag) {
797
case 'e': // Enum value
798
buf.getInt(); // (Two shorts, actually.)
799
break;
800
case '@':
801
skipAnnotation(buf, true);
802
break;
803
case '[':
804
skipArray(buf);
805
break;
806
default:
807
// Class, primitive, or String
808
buf.getShort();
809
}
810
}
811
812
/**
813
* Skips the array value at the current position in the specified byte
814
* buffer. The cursor of the byte buffer must point to an array value
815
* struct.
816
*/
817
private static void skipArray(ByteBuffer buf) {
818
int length = buf.getShort() & 0xFFFF;
819
for (int i = 0; i < length; i++)
820
skipMemberValue(buf);
821
}
822
823
/**
824
* Searches for given {@code element} in given {@code array} by identity.
825
* Returns {@code true} if found {@code false} if not.
826
*/
827
private static boolean contains(Object[] array, Object element) {
828
for (Object e : array)
829
if (e == element)
830
return true;
831
return false;
832
}
833
834
/*
835
* This method converts the annotation map returned by the parseAnnotations()
836
* method to an array. It is called by Field.getDeclaredAnnotations(),
837
* Method.getDeclaredAnnotations(), and Constructor.getDeclaredAnnotations().
838
* This avoids the reflection classes to load the Annotation class until
839
* it is needed.
840
*/
841
private static final Annotation[] EMPTY_ANNOTATION_ARRAY = new Annotation[0];
842
public static Annotation[] toArray(Map<Class<? extends Annotation>, Annotation> annotations) {
843
return annotations.values().toArray(EMPTY_ANNOTATION_ARRAY);
844
}
845
846
static Annotation[] getEmptyAnnotationArray() { return EMPTY_ANNOTATION_ARRAY; }
847
}
848
849