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 */ parseAnnotations( byte[] rawAnnotations, ConstantPool constPool, Class<?> container)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 parseSelectAnnotations( byte[] rawAnnotations, ConstantPool constPool, Class<?> container, Class<? extends Annotation> ... selectAnnotationClasses)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 parseAnnotations2( byte[] rawAnnotations, ConstantPool constPool, Class<?> container, Class<? extends Annotation>[] selectAnnotationClasses)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 */ parseParameterAnnotations( byte[] rawAnnotations, ConstantPool constPool, Class<?> container)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 parseParameterAnnotations2( byte[] rawAnnotations, ConstantPool constPool, Class<?> container)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 */ parseAnnotation(ByteBuffer buf, ConstantPool constPool, Class<?> container, boolean exceptionOnMissingAnnotationClass)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") parseAnnotation2(ByteBuffer buf, ConstantPool constPool, Class<?> container, boolean exceptionOnMissingAnnotationClass, Class<? extends Annotation>[] selectAnnotationClasses)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") annotationForMap(final Class<? extends Annotation> type, final Map<String, Object> memberValues)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 Proxy.isProxyClass(memberType) 360 ? memberType.getInterfaces()[0].getName() 361 : memberType.getName()); 362 } else if (!(result instanceof ExceptionProxy) && 363 !memberType.isInstance(result)) { 364 if (result instanceof Annotation) { 365 result = new AnnotationTypeMismatchExceptionProxy( 366 result.toString()); 367 } else { 368 result = new AnnotationTypeMismatchExceptionProxy( 369 result.getClass().getName() + "[" + result + "]"); 370 } 371 } 372 return result; 373 } 374 375 /** 376 * Parses the primitive or String annotation member value indicated by 377 * the specified tag byte at the current position in the specified byte 378 * buffer, resolving constant reference in the specified constant pool. 379 * The cursor of the byte buffer must point to an annotation member value 380 * of the type indicated by the specified tag, as described in the 381 * RuntimeVisibleAnnotations_attribute: 382 * 383 * u2 const_value_index; 384 */ 385 private static Object parseConst(int tag, 386 ByteBuffer buf, ConstantPool constPool) { 387 int constIndex = buf.getShort() & 0xFFFF; 388 switch(tag) { 389 case 'B': 390 return Byte.valueOf((byte) constPool.getIntAt(constIndex)); 391 case 'C': 392 return Character.valueOf((char) constPool.getIntAt(constIndex)); 393 case 'D': 394 return Double.valueOf(constPool.getDoubleAt(constIndex)); 395 case 'F': 396 return Float.valueOf(constPool.getFloatAt(constIndex)); 397 case 'I': 398 return Integer.valueOf(constPool.getIntAt(constIndex)); 399 case 'J': 400 return Long.valueOf(constPool.getLongAt(constIndex)); 401 case 'S': 402 return Short.valueOf((short) constPool.getIntAt(constIndex)); 403 case 'Z': 404 return Boolean.valueOf(constPool.getIntAt(constIndex) != 0); 405 case 's': 406 return constPool.getUTF8At(constIndex); 407 default: 408 throw new AnnotationFormatError( 409 "Invalid member-value tag in annotation: " + tag); 410 } 411 } 412 413 /** 414 * Parses the Class member value at the current position in the 415 * specified byte buffer, resolving constant references in the specified 416 * constant pool. The cursor of the byte buffer must point to a "class 417 * info index" as described in the RuntimeVisibleAnnotations_attribute: 418 * 419 * u2 class_info_index; 420 */ 421 private static Object parseClassValue(ByteBuffer buf, 422 ConstantPool constPool, 423 Class<?> container) { 424 int classIndex = buf.getShort() & 0xFFFF; 425 try { 426 String sig = constPool.getUTF8At(classIndex); 427 return parseSig(sig, container); 428 } catch (NoClassDefFoundError e) { 429 return new TypeNotPresentExceptionProxy("[unknown]", e); 430 } catch (TypeNotPresentException e) { 431 return new TypeNotPresentExceptionProxy(e.typeName(), e.getCause()); 432 } 433 } 434 435 private static Class<?> parseSig(String sig, Class<?> container) { 436 if (sig.equals("V")) return void.class; 437 SignatureParser parser = SignatureParser.make(); 438 TypeSignature typeSig = parser.parseTypeSig(sig); 439 GenericsFactory factory = CoreReflectionFactory.make(container, ClassScope.make(container)); 440 Reifier reify = Reifier.make(factory); 441 typeSig.accept(reify); 442 Type result = reify.getResult(); 443 return toClass(result); 444 } 445 static Class<?> toClass(Type o) { 446 if (o instanceof GenericArrayType) 447 return Array.newInstance(toClass(((GenericArrayType)o).getGenericComponentType()), 448 0) 449 .getClass(); 450 return (Class)o; 451 } 452 453 /** 454 * Parses the enum constant member value at the current position in the 455 * specified byte buffer, resolving constant references in the specified 456 * constant pool. The cursor of the byte buffer must point to a 457 * "enum_const_value structure" as described in the 458 * RuntimeVisibleAnnotations_attribute: 459 * 460 * { 461 * u2 type_name_index; 462 * u2 const_name_index; 463 * } enum_const_value; 464 */ 465 @SuppressWarnings({"rawtypes", "unchecked"}) 466 private static Object parseEnumValue(Class<? extends Enum> enumType, ByteBuffer buf, 467 ConstantPool constPool, 468 Class<?> container) { 469 int typeNameIndex = buf.getShort() & 0xFFFF; 470 String typeName = constPool.getUTF8At(typeNameIndex); 471 int constNameIndex = buf.getShort() & 0xFFFF; 472 String constName = constPool.getUTF8At(constNameIndex); 473 if (!enumType.isEnum() || enumType != parseSig(typeName, container)) { 474 return new AnnotationTypeMismatchExceptionProxy( 475 typeName.substring(1, typeName.length() - 1).replace('/', '.') + "." + constName); 476 } 477 478 try { 479 return Enum.valueOf(enumType, constName); 480 } catch(IllegalArgumentException e) { 481 return new EnumConstantNotPresentExceptionProxy( 482 (Class<? extends Enum<?>>)enumType, constName); 483 } 484 } 485 486 /** 487 * Parses the array value at the current position in the specified byte 488 * buffer, resolving constant references in the specified constant pool. 489 * The cursor of the byte buffer must point to an array value struct 490 * as specified in the RuntimeVisibleAnnotations_attribute: 491 * 492 * { 493 * u2 num_values; 494 * member_value values[num_values]; 495 * } array_value; 496 * 497 * If the array values do not match arrayType, an 498 * AnnotationTypeMismatchExceptionProxy will be returned. 499 */ 500 @SuppressWarnings("unchecked") 501 private static Object parseArray(Class<?> arrayType, 502 ByteBuffer buf, 503 ConstantPool constPool, 504 Class<?> container) { 505 int length = buf.getShort() & 0xFFFF; // Number of array components 506 Class<?> componentType = arrayType.getComponentType(); 507 508 if (componentType == byte.class) { 509 return parseByteArray(length, buf, constPool); 510 } else if (componentType == char.class) { 511 return parseCharArray(length, buf, constPool); 512 } else if (componentType == double.class) { 513 return parseDoubleArray(length, buf, constPool); 514 } else if (componentType == float.class) { 515 return parseFloatArray(length, buf, constPool); 516 } else if (componentType == int.class) { 517 return parseIntArray(length, buf, constPool); 518 } else if (componentType == long.class) { 519 return parseLongArray(length, buf, constPool); 520 } else if (componentType == short.class) { 521 return parseShortArray(length, buf, constPool); 522 } else if (componentType == boolean.class) { 523 return parseBooleanArray(length, buf, constPool); 524 } else if (componentType == String.class) { 525 return parseStringArray(length, buf, constPool); 526 } else if (componentType == Class.class) { 527 return parseClassArray(length, buf, constPool, container); 528 } else if (componentType.isEnum()) { 529 return parseEnumArray(length, (Class<? extends Enum<?>>)componentType, buf, 530 constPool, container); 531 } else if (componentType.isAnnotation()) { 532 return parseAnnotationArray(length, (Class <? extends Annotation>)componentType, buf, 533 constPool, container); 534 } else { 535 return parseUnknownArray(length, buf); 536 } 537 } 538 539 private static Object parseByteArray(int length, 540 ByteBuffer buf, ConstantPool constPool) { 541 byte[] result = new byte[length]; 542 boolean typeMismatch = false; 543 int tag = 0; 544 545 for (int i = 0; i < length; i++) { 546 tag = buf.get(); 547 if (tag == 'B') { 548 int index = buf.getShort() & 0xFFFF; 549 result[i] = (byte) constPool.getIntAt(index); 550 } else { 551 skipMemberValue(tag, buf); 552 typeMismatch = true; 553 } 554 } 555 return typeMismatch ? exceptionProxy(tag) : result; 556 } 557 558 private static Object parseCharArray(int length, 559 ByteBuffer buf, ConstantPool constPool) { 560 char[] result = new char[length]; 561 boolean typeMismatch = false; 562 byte tag = 0; 563 564 for (int i = 0; i < length; i++) { 565 tag = buf.get(); 566 if (tag == 'C') { 567 int index = buf.getShort() & 0xFFFF; 568 result[i] = (char) constPool.getIntAt(index); 569 } else { 570 skipMemberValue(tag, buf); 571 typeMismatch = true; 572 } 573 } 574 return typeMismatch ? exceptionProxy(tag) : result; 575 } 576 577 private static Object parseDoubleArray(int length, 578 ByteBuffer buf, ConstantPool constPool) { 579 double[] result = new double[length]; 580 boolean typeMismatch = false; 581 int tag = 0; 582 583 for (int i = 0; i < length; i++) { 584 tag = buf.get(); 585 if (tag == 'D') { 586 int index = buf.getShort() & 0xFFFF; 587 result[i] = constPool.getDoubleAt(index); 588 } else { 589 skipMemberValue(tag, buf); 590 typeMismatch = true; 591 } 592 } 593 return typeMismatch ? exceptionProxy(tag) : result; 594 } 595 596 private static Object parseFloatArray(int length, 597 ByteBuffer buf, ConstantPool constPool) { 598 float[] result = new float[length]; 599 boolean typeMismatch = false; 600 int tag = 0; 601 602 for (int i = 0; i < length; i++) { 603 tag = buf.get(); 604 if (tag == 'F') { 605 int index = buf.getShort() & 0xFFFF; 606 result[i] = constPool.getFloatAt(index); 607 } else { 608 skipMemberValue(tag, buf); 609 typeMismatch = true; 610 } 611 } 612 return typeMismatch ? exceptionProxy(tag) : result; 613 } 614 615 private static Object parseIntArray(int length, 616 ByteBuffer buf, ConstantPool constPool) { 617 int[] result = new int[length]; 618 boolean typeMismatch = false; 619 int tag = 0; 620 621 for (int i = 0; i < length; i++) { 622 tag = buf.get(); 623 if (tag == 'I') { 624 int index = buf.getShort() & 0xFFFF; 625 result[i] = constPool.getIntAt(index); 626 } else { 627 skipMemberValue(tag, buf); 628 typeMismatch = true; 629 } 630 } 631 return typeMismatch ? exceptionProxy(tag) : result; 632 } 633 634 private static Object parseLongArray(int length, 635 ByteBuffer buf, ConstantPool constPool) { 636 long[] result = new long[length]; 637 boolean typeMismatch = false; 638 int tag = 0; 639 640 for (int i = 0; i < length; i++) { 641 tag = buf.get(); 642 if (tag == 'J') { 643 int index = buf.getShort() & 0xFFFF; 644 result[i] = constPool.getLongAt(index); 645 } else { 646 skipMemberValue(tag, buf); 647 typeMismatch = true; 648 } 649 } 650 return typeMismatch ? exceptionProxy(tag) : result; 651 } 652 653 private static Object parseShortArray(int length, 654 ByteBuffer buf, ConstantPool constPool) { 655 short[] result = new short[length]; 656 boolean typeMismatch = false; 657 int tag = 0; 658 659 for (int i = 0; i < length; i++) { 660 tag = buf.get(); 661 if (tag == 'S') { 662 int index = buf.getShort() & 0xFFFF; 663 result[i] = (short) constPool.getIntAt(index); 664 } else { 665 skipMemberValue(tag, buf); 666 typeMismatch = true; 667 } 668 } 669 return typeMismatch ? exceptionProxy(tag) : result; 670 } 671 672 private static Object parseBooleanArray(int length, 673 ByteBuffer buf, ConstantPool constPool) { 674 boolean[] result = new boolean[length]; 675 boolean typeMismatch = false; 676 int tag = 0; 677 678 for (int i = 0; i < length; i++) { 679 tag = buf.get(); 680 if (tag == 'Z') { 681 int index = buf.getShort() & 0xFFFF; 682 result[i] = (constPool.getIntAt(index) != 0); 683 } else { 684 skipMemberValue(tag, buf); 685 typeMismatch = true; 686 } 687 } 688 return typeMismatch ? exceptionProxy(tag) : result; 689 } 690 691 private static Object parseStringArray(int length, 692 ByteBuffer buf, ConstantPool constPool) { 693 String[] result = new String[length]; 694 boolean typeMismatch = false; 695 int tag = 0; 696 697 for (int i = 0; i < length; i++) { 698 tag = buf.get(); 699 if (tag == 's') { 700 int index = buf.getShort() & 0xFFFF; 701 result[i] = constPool.getUTF8At(index); 702 } else { 703 skipMemberValue(tag, buf); 704 typeMismatch = true; 705 } 706 } 707 return typeMismatch ? exceptionProxy(tag) : result; 708 } 709 710 private static Object parseClassArray(int length, 711 ByteBuffer buf, 712 ConstantPool constPool, 713 Class<?> container) { 714 return parseArrayElements(new Class<?>[length], 715 buf, 'c', () -> parseClassValue(buf, constPool, container)); 716 } 717 718 private static Object parseEnumArray(int length, Class<? extends Enum<?>> enumType, 719 ByteBuffer buf, 720 ConstantPool constPool, 721 Class<?> container) { 722 return parseArrayElements((Object[]) Array.newInstance(enumType, length), 723 buf, 'e', () -> parseEnumValue(enumType, buf, constPool, container)); 724 } 725 726 private static Object parseAnnotationArray(int length, 727 Class<? extends Annotation> annotationType, 728 ByteBuffer buf, 729 ConstantPool constPool, 730 Class<?> container) { 731 return parseArrayElements((Object[]) Array.newInstance(annotationType, length), 732 buf, '@', () -> parseAnnotation(buf, constPool, container, true)); 733 } 734 735 private static Object parseArrayElements(Object[] result, 736 ByteBuffer buf, 737 int expectedTag, 738 Supplier<Object> parseElement) { 739 Object exceptionProxy = null; 740 for (int i = 0; i < result.length; i++) { 741 int tag = buf.get(); 742 if (tag == expectedTag) { 743 Object value = parseElement.get(); 744 if (value instanceof ExceptionProxy) { 745 if (exceptionProxy == null) exceptionProxy = (ExceptionProxy) value; 746 } else { 747 result[i] = value; 748 } 749 } else { 750 skipMemberValue(tag, buf); 751 if (exceptionProxy == null) exceptionProxy = exceptionProxy(tag); 752 } 753 } 754 return (exceptionProxy != null) ? exceptionProxy : result; 755 } 756 757 private static Object parseUnknownArray(int length, 758 ByteBuffer buf) { 759 int tag = 0; 760 761 for (int i = 0; i < length; i++) { 762 tag = buf.get(); 763 skipMemberValue(tag, buf); 764 } 765 766 return exceptionProxy(tag); 767 } 768 769 /** 770 * Returns an appropriate exception proxy for a mismatching array 771 * annotation where the erroneous array has the specified tag. 772 */ 773 private static ExceptionProxy exceptionProxy(int tag) { 774 return new AnnotationTypeMismatchExceptionProxy( 775 "Array with component tag: " + (tag == 0 ? "0" : (char) tag)); 776 } 777 778 /** 779 * Skips the annotation at the current position in the specified 780 * byte buffer. The cursor of the byte buffer must point to 781 * an "annotation structure" OR two bytes into an annotation 782 * structure (i.e., after the type index). 783 * 784 * @param complete true if the byte buffer points to the beginning 785 * of an annotation structure (rather than two bytes in). 786 */ 787 private static void skipAnnotation(ByteBuffer buf, boolean complete) { 788 if (complete) 789 buf.getShort(); // Skip type index 790 int numMembers = buf.getShort() & 0xFFFF; 791 for (int i = 0; i < numMembers; i++) { 792 buf.getShort(); // Skip memberNameIndex 793 skipMemberValue(buf); 794 } 795 } 796 797 /** 798 * Skips the annotation member value at the current position in the 799 * specified byte buffer. The cursor of the byte buffer must point to a 800 * "member_value structure." 801 */ 802 private static void skipMemberValue(ByteBuffer buf) { 803 int tag = buf.get(); 804 skipMemberValue(tag, buf); 805 } 806 807 /** 808 * Skips the annotation member value at the current position in the 809 * specified byte buffer. The cursor of the byte buffer must point 810 * immediately after the tag in a "member_value structure." 811 */ 812 private static void skipMemberValue(int tag, ByteBuffer buf) { 813 switch(tag) { 814 case 'e': // Enum value 815 buf.getInt(); // (Two shorts, actually.) 816 break; 817 case '@': 818 skipAnnotation(buf, true); 819 break; 820 case '[': 821 skipArray(buf); 822 break; 823 default: 824 // Class, primitive, or String 825 buf.getShort(); 826 } 827 } 828 829 /** 830 * Skips the array value at the current position in the specified byte 831 * buffer. The cursor of the byte buffer must point to an array value 832 * struct. 833 */ 834 private static void skipArray(ByteBuffer buf) { 835 int length = buf.getShort() & 0xFFFF; 836 for (int i = 0; i < length; i++) 837 skipMemberValue(buf); 838 } 839 840 /** 841 * Searches for given {@code element} in given {@code array} by identity. 842 * Returns {@code true} if found {@code false} if not. 843 */ 844 private static boolean contains(Object[] array, Object element) { 845 for (Object e : array) 846 if (e == element) 847 return true; 848 return false; 849 } 850 851 /* 852 * This method converts the annotation map returned by the parseAnnotations() 853 * method to an array. It is called by Field.getDeclaredAnnotations(), 854 * Method.getDeclaredAnnotations(), and Constructor.getDeclaredAnnotations(). 855 * This avoids the reflection classes to load the Annotation class until 856 * it is needed. 857 */ 858 private static final Annotation[] EMPTY_ANNOTATION_ARRAY = new Annotation[0]; 859 public static Annotation[] toArray(Map<Class<? extends Annotation>, Annotation> annotations) { 860 return annotations.values().toArray(EMPTY_ANNOTATION_ARRAY); 861 } 862 863 static Annotation[] getEmptyAnnotationArray() { return EMPTY_ANNOTATION_ARRAY; } 864 } 865