1 /* 2 * Copyright (c) 2003, 2020, 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 try { 241 sig = constPool.getUTF8At(typeIndex); 242 annotationClass = (Class<? extends Annotation>)parseSig(sig, container); 243 } catch (IllegalArgumentException ex) { 244 // support obsolete early jsr175 format class files 245 annotationClass = (Class<? extends Annotation>)constPool.getClassAt(typeIndex); 246 } 247 } catch (NoClassDefFoundError e) { 248 if (exceptionOnMissingAnnotationClass) 249 // note: at this point sig is "[unknown]" or VM-style 250 // name instead of a binary name 251 throw new TypeNotPresentException(sig, e); 252 skipAnnotation(buf, false); 253 return null; 254 } 255 catch (TypeNotPresentException e) { 256 if (exceptionOnMissingAnnotationClass) 257 throw e; 258 skipAnnotation(buf, false); 259 return null; 260 } 261 if (selectAnnotationClasses != null && !contains(selectAnnotationClasses, annotationClass)) { 262 skipAnnotation(buf, false); 263 return null; 264 } 265 AnnotationType type = null; 266 try { 267 type = AnnotationType.getInstance(annotationClass); 268 } catch (IllegalArgumentException e) { 269 skipAnnotation(buf, false); 270 return null; 271 } 272 273 Map<String, Class<?>> memberTypes = type.memberTypes(); 274 Map<String, Object> memberValues = 275 new LinkedHashMap<String, Object>(type.memberDefaults()); 276 277 int numMembers = buf.getShort() & 0xFFFF; 278 for (int i = 0; i < numMembers; i++) { 279 int memberNameIndex = buf.getShort() & 0xFFFF; 280 String memberName = constPool.getUTF8At(memberNameIndex); 281 Class<?> memberType = memberTypes.get(memberName); 282 283 if (memberType == null) { 284 // Member is no longer present in annotation type; ignore it 285 skipMemberValue(buf); 286 } else { 287 Object value = parseMemberValue(memberType, buf, constPool, container); 288 if (value instanceof AnnotationTypeMismatchExceptionProxy) 289 ((AnnotationTypeMismatchExceptionProxy) value). 290 setMember(type.members().get(memberName)); 291 memberValues.put(memberName, value); 292 } 293 } 294 return annotationForMap(annotationClass, memberValues); 295 } 296 297 /** 298 * Returns an annotation of the given type backed by the given 299 * member {@literal ->} value map. 300 */ 301 public static Annotation annotationForMap(final Class<? extends Annotation> type, 302 final Map<String, Object> memberValues) 303 { 304 return AccessController.doPrivileged(new PrivilegedAction<Annotation>() { 305 public Annotation run() { 306 return (Annotation) Proxy.newProxyInstance( 307 type.getClassLoader(), new Class<?>[] { type }, 308 new AnnotationInvocationHandler(type, memberValues)); 309 }}); 310 } 311 312 /** 313 * Parses the annotation member value at the current position in the 314 * specified byte buffer, resolving constant references in the specified 315 * constant pool. The cursor of the byte buffer must point to a 316 * "member_value structure" as described in the 317 * RuntimeVisibleAnnotations_attribute: 318 * 319 * member_value { 320 * u1 tag; 321 * union { 322 * u2 const_value_index; 323 * { 324 * u2 type_name_index; 325 * u2 const_name_index; 326 * } enum_const_value; 327 * u2 class_info_index; 328 * annotation annotation_value; 329 * { 330 * u2 num_values; 331 * member_value values[num_values]; 332 * } array_value; 333 * } value; 334 * } 335 * 336 * The member must be of the indicated type. If it is not, this 337 * method returns an AnnotationTypeMismatchExceptionProxy. 338 */ 339 @SuppressWarnings("unchecked") 340 public static Object parseMemberValue(Class<?> memberType, 341 ByteBuffer buf, 342 ConstantPool constPool, 343 Class<?> container) { 344 Object result = null; 345 int tag = buf.get(); 346 switch(tag) { 347 case 'e': 348 return parseEnumValue((Class<? extends Enum<?>>)memberType, buf, constPool, container); 349 case 'c': 350 result = parseClassValue(buf, constPool, container); 351 break; 352 case '@': 353 result = parseAnnotation(buf, constPool, container, true); 354 break; 355 case '[': 356 return parseArray(memberType, buf, constPool, container); 357 default: 358 result = parseConst(tag, buf, constPool); 359 } 360 361 if (!(result instanceof ExceptionProxy) && 362 !memberType.isInstance(result)) 363 result = new AnnotationTypeMismatchExceptionProxy( 364 result.getClass() + "[" + result + "]"); 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 try { 420 String sig = constPool.getUTF8At(classIndex); 421 return parseSig(sig, container); 422 } catch (IllegalArgumentException ex) { 423 // support obsolete early jsr175 format class files 424 return constPool.getClassAt(classIndex); 425 } 426 } catch (NoClassDefFoundError e) { 427 return new TypeNotPresentExceptionProxy("[unknown]", e); 428 } 429 catch (TypeNotPresentException e) { 430 return new TypeNotPresentExceptionProxy(e.typeName(), e.getCause()); 431 } 432 } 433 434 private static Class<?> parseSig(String sig, Class<?> container) { 435 if (sig.equals("V")) return void.class; 436 SignatureParser parser = SignatureParser.make(); 437 TypeSignature typeSig = parser.parseTypeSig(sig); 438 GenericsFactory factory = CoreReflectionFactory.make(container, ClassScope.make(container)); 439 Reifier reify = Reifier.make(factory); 440 typeSig.accept(reify); 441 Type result = reify.getResult(); 442 return toClass(result); 443 } 444 static Class<?> toClass(Type o) { 445 if (o instanceof GenericArrayType) 446 return Array.newInstance(toClass(((GenericArrayType)o).getGenericComponentType()), 447 0) 448 .getClass(); 449 return (Class)o; 450 } 451 452 /** 453 * Parses the enum constant member value at the current position in the 454 * specified byte buffer, resolving constant references in the specified 455 * constant pool. The cursor of the byte buffer must point to a 456 * "enum_const_value structure" as described in the 457 * RuntimeVisibleAnnotations_attribute: 458 * 459 * { 460 * u2 type_name_index; 461 * u2 const_name_index; 462 * } enum_const_value; 463 */ 464 @SuppressWarnings({"rawtypes", "unchecked"}) 465 private static Object parseEnumValue(Class<? extends Enum> enumType, ByteBuffer buf, 466 ConstantPool constPool, 467 Class<?> container) { 468 int typeNameIndex = buf.getShort() & 0xFFFF; 469 String typeName = constPool.getUTF8At(typeNameIndex); 470 int constNameIndex = buf.getShort() & 0xFFFF; 471 String constName = constPool.getUTF8At(constNameIndex); 472 473 if (!typeName.endsWith(";")) { 474 // support now-obsolete early jsr175-format class files. 475 if (!enumType.getName().equals(typeName)) 476 return new AnnotationTypeMismatchExceptionProxy( 477 typeName + "." + constName); 478 } else if (enumType != parseSig(typeName, container)) { 479 return new AnnotationTypeMismatchExceptionProxy( 480 typeName + "." + constName); 481 } 482 483 try { 484 return Enum.valueOf(enumType, constName); 485 } catch(IllegalArgumentException e) { 486 return new EnumConstantNotPresentExceptionProxy( 487 (Class<? extends Enum<?>>)enumType, constName); 488 } 489 } 490 491 /** 492 * Parses the array value at the current position in the specified byte 493 * buffer, resolving constant references in the specified constant pool. 494 * The cursor of the byte buffer must point to an array value struct 495 * as specified in the RuntimeVisibleAnnotations_attribute: 496 * 497 * { 498 * u2 num_values; 499 * member_value values[num_values]; 500 * } array_value; 501 * 502 * If the array values do not match arrayType, an 503 * AnnotationTypeMismatchExceptionProxy will be returned. 504 */ 505 @SuppressWarnings("unchecked") 506 private static Object parseArray(Class<?> arrayType, 507 ByteBuffer buf, 508 ConstantPool constPool, 509 Class<?> container) { 510 int length = buf.getShort() & 0xFFFF; // Number of array components 511 Class<?> componentType = arrayType.getComponentType(); 512 513 if (componentType == byte.class) { 514 return parseByteArray(length, buf, constPool); 515 } else if (componentType == char.class) { 516 return parseCharArray(length, buf, constPool); 517 } else if (componentType == double.class) { 518 return parseDoubleArray(length, buf, constPool); 519 } else if (componentType == float.class) { 520 return parseFloatArray(length, buf, constPool); 521 } else if (componentType == int.class) { 522 return parseIntArray(length, buf, constPool); 523 } else if (componentType == long.class) { 524 return parseLongArray(length, buf, constPool); 525 } else if (componentType == short.class) { 526 return parseShortArray(length, buf, constPool); 527 } else if (componentType == boolean.class) { 528 return parseBooleanArray(length, buf, constPool); 529 } else if (componentType == String.class) { 530 return parseStringArray(length, buf, constPool); 531 } else if (componentType == Class.class) { 532 return parseClassArray(length, buf, constPool, container); 533 } else if (componentType.isEnum()) { 534 return parseEnumArray(length, (Class<? extends Enum<?>>)componentType, buf, 535 constPool, container); 536 } else { 537 assert componentType.isAnnotation(); 538 return parseAnnotationArray(length, (Class <? extends Annotation>)componentType, buf, 539 constPool, container); 540 } 541 } 542 543 private static Object parseByteArray(int length, 544 ByteBuffer buf, ConstantPool constPool) { 545 byte[] result = new byte[length]; 546 boolean typeMismatch = false; 547 int tag = 0; 548 549 for (int i = 0; i < length; i++) { 550 tag = buf.get(); 551 if (tag == 'B') { 552 int index = buf.getShort() & 0xFFFF; 553 result[i] = (byte) constPool.getIntAt(index); 554 } else { 555 skipMemberValue(tag, buf); 556 typeMismatch = true; 557 } 558 } 559 return typeMismatch ? exceptionProxy(tag) : result; 560 } 561 562 private static Object parseCharArray(int length, 563 ByteBuffer buf, ConstantPool constPool) { 564 char[] result = new char[length]; 565 boolean typeMismatch = false; 566 byte tag = 0; 567 568 for (int i = 0; i < length; i++) { 569 tag = buf.get(); 570 if (tag == 'C') { 571 int index = buf.getShort() & 0xFFFF; 572 result[i] = (char) constPool.getIntAt(index); 573 } else { 574 skipMemberValue(tag, buf); 575 typeMismatch = true; 576 } 577 } 578 return typeMismatch ? exceptionProxy(tag) : result; 579 } 580 581 private static Object parseDoubleArray(int length, 582 ByteBuffer buf, ConstantPool constPool) { 583 double[] result = new double[length]; 584 boolean typeMismatch = false; 585 int tag = 0; 586 587 for (int i = 0; i < length; i++) { 588 tag = buf.get(); 589 if (tag == 'D') { 590 int index = buf.getShort() & 0xFFFF; 591 result[i] = constPool.getDoubleAt(index); 592 } else { 593 skipMemberValue(tag, buf); 594 typeMismatch = true; 595 } 596 } 597 return typeMismatch ? exceptionProxy(tag) : result; 598 } 599 600 private static Object parseFloatArray(int length, 601 ByteBuffer buf, ConstantPool constPool) { 602 float[] result = new float[length]; 603 boolean typeMismatch = false; 604 int tag = 0; 605 606 for (int i = 0; i < length; i++) { 607 tag = buf.get(); 608 if (tag == 'F') { 609 int index = buf.getShort() & 0xFFFF; 610 result[i] = constPool.getFloatAt(index); 611 } else { 612 skipMemberValue(tag, buf); 613 typeMismatch = true; 614 } 615 } 616 return typeMismatch ? exceptionProxy(tag) : result; 617 } 618 619 private static Object parseIntArray(int length, 620 ByteBuffer buf, ConstantPool constPool) { 621 int[] result = new int[length]; 622 boolean typeMismatch = false; 623 int tag = 0; 624 625 for (int i = 0; i < length; i++) { 626 tag = buf.get(); 627 if (tag == 'I') { 628 int index = buf.getShort() & 0xFFFF; 629 result[i] = constPool.getIntAt(index); 630 } else { 631 skipMemberValue(tag, buf); 632 typeMismatch = true; 633 } 634 } 635 return typeMismatch ? exceptionProxy(tag) : result; 636 } 637 638 private static Object parseLongArray(int length, 639 ByteBuffer buf, ConstantPool constPool) { 640 long[] result = new long[length]; 641 boolean typeMismatch = false; 642 int tag = 0; 643 644 for (int i = 0; i < length; i++) { 645 tag = buf.get(); 646 if (tag == 'J') { 647 int index = buf.getShort() & 0xFFFF; 648 result[i] = constPool.getLongAt(index); 649 } else { 650 skipMemberValue(tag, buf); 651 typeMismatch = true; 652 } 653 } 654 return typeMismatch ? exceptionProxy(tag) : result; 655 } 656 657 private static Object parseShortArray(int length, 658 ByteBuffer buf, ConstantPool constPool) { 659 short[] result = new short[length]; 660 boolean typeMismatch = false; 661 int tag = 0; 662 663 for (int i = 0; i < length; i++) { 664 tag = buf.get(); 665 if (tag == 'S') { 666 int index = buf.getShort() & 0xFFFF; 667 result[i] = (short) constPool.getIntAt(index); 668 } else { 669 skipMemberValue(tag, buf); 670 typeMismatch = true; 671 } 672 } 673 return typeMismatch ? exceptionProxy(tag) : result; 674 } 675 676 private static Object parseBooleanArray(int length, 677 ByteBuffer buf, ConstantPool constPool) { 678 boolean[] result = new boolean[length]; 679 boolean typeMismatch = false; 680 int tag = 0; 681 682 for (int i = 0; i < length; i++) { 683 tag = buf.get(); 684 if (tag == 'Z') { 685 int index = buf.getShort() & 0xFFFF; 686 result[i] = (constPool.getIntAt(index) != 0); 687 } else { 688 skipMemberValue(tag, buf); 689 typeMismatch = true; 690 } 691 } 692 return typeMismatch ? exceptionProxy(tag) : result; 693 } 694 695 private static Object parseStringArray(int length, 696 ByteBuffer buf, ConstantPool constPool) { 697 String[] result = new String[length]; 698 boolean typeMismatch = false; 699 int tag = 0; 700 701 for (int i = 0; i < length; i++) { 702 tag = buf.get(); 703 if (tag == 's') { 704 int index = buf.getShort() & 0xFFFF; 705 result[i] = constPool.getUTF8At(index); 706 } else { 707 skipMemberValue(tag, buf); 708 typeMismatch = true; 709 } 710 } 711 return typeMismatch ? exceptionProxy(tag) : result; 712 } 713 714 private static Object parseClassArray(int length, 715 ByteBuffer buf, 716 ConstantPool constPool, 717 Class<?> container) { 718 return parseArrayElements(new Class<?>[length], 719 buf, 'c', () -> parseClassValue(buf, constPool, container)); 720 } 721 722 private static Object parseEnumArray(int length, Class<? extends Enum<?>> enumType, 723 ByteBuffer buf, 724 ConstantPool constPool, 725 Class<?> container) { 726 return parseArrayElements((Object[]) Array.newInstance(enumType, length), 727 buf, 'e', () -> parseEnumValue(enumType, buf, constPool, container)); 728 } 729 730 private static Object parseAnnotationArray(int length, 731 Class<? extends Annotation> annotationType, 732 ByteBuffer buf, 733 ConstantPool constPool, 734 Class<?> container) { 735 return parseArrayElements((Object[]) Array.newInstance(annotationType, length), 736 buf, '@', () -> parseAnnotation(buf, constPool, container, true)); 737 } 738 739 private static Object parseArrayElements(Object[] result, 740 ByteBuffer buf, 741 int expectedTag, 742 Supplier<Object> parseElement) { 743 Object exceptionProxy = null; 744 for (int i = 0; i < result.length; i++) { 745 int tag = buf.get(); 746 if (tag == expectedTag) { 747 Object value = parseElement.get(); 748 if (value instanceof ExceptionProxy) { 749 if (exceptionProxy == null) exceptionProxy = (ExceptionProxy) value; 750 } else { 751 result[i] = value; 752 } 753 } else { 754 skipMemberValue(tag, buf); 755 if (exceptionProxy == null) exceptionProxy = exceptionProxy(tag); 756 } 757 } 758 return (exceptionProxy != null) ? exceptionProxy : result; 759 } 760 761 /** 762 * Returns an appropriate exception proxy for a mismatching array 763 * annotation where the erroneous array has the specified tag. 764 */ 765 private static ExceptionProxy exceptionProxy(int tag) { 766 return new AnnotationTypeMismatchExceptionProxy( 767 "Array with component tag: " + tag); 768 } 769 770 /** 771 * Skips the annotation at the current position in the specified 772 * byte buffer. The cursor of the byte buffer must point to 773 * an "annotation structure" OR two bytes into an annotation 774 * structure (i.e., after the type index). 775 * 776 * @param complete true if the byte buffer points to the beginning 777 * of an annotation structure (rather than two bytes in). 778 */ 779 private static void skipAnnotation(ByteBuffer buf, boolean complete) { 780 if (complete) 781 buf.getShort(); // Skip type index 782 int numMembers = buf.getShort() & 0xFFFF; 783 for (int i = 0; i < numMembers; i++) { 784 buf.getShort(); // Skip memberNameIndex 785 skipMemberValue(buf); 786 } 787 } 788 789 /** 790 * Skips the annotation member value at the current position in the 791 * specified byte buffer. The cursor of the byte buffer must point to a 792 * "member_value structure." 793 */ 794 private static void skipMemberValue(ByteBuffer buf) { 795 int tag = buf.get(); 796 skipMemberValue(tag, buf); 797 } 798 799 /** 800 * Skips the annotation member value at the current position in the 801 * specified byte buffer. The cursor of the byte buffer must point 802 * immediately after the tag in a "member_value structure." 803 */ 804 private static void skipMemberValue(int tag, ByteBuffer buf) { 805 switch(tag) { 806 case 'e': // Enum value 807 buf.getInt(); // (Two shorts, actually.) 808 break; 809 case '@': 810 skipAnnotation(buf, true); 811 break; 812 case '[': 813 skipArray(buf); 814 break; 815 default: 816 // Class, primitive, or String 817 buf.getShort(); 818 } 819 } 820 821 /** 822 * Skips the array value at the current position in the specified byte 823 * buffer. The cursor of the byte buffer must point to an array value 824 * struct. 825 */ 826 private static void skipArray(ByteBuffer buf) { 827 int length = buf.getShort() & 0xFFFF; 828 for (int i = 0; i < length; i++) 829 skipMemberValue(buf); 830 } 831 832 /** 833 * Searches for given {@code element} in given {@code array} by identity. 834 * Returns {@code true} if found {@code false} if not. 835 */ 836 private static boolean contains(Object[] array, Object element) { 837 for (Object e : array) 838 if (e == element) 839 return true; 840 return false; 841 } 842 843 /* 844 * This method converts the annotation map returned by the parseAnnotations() 845 * method to an array. It is called by Field.getDeclaredAnnotations(), 846 * Method.getDeclaredAnnotations(), and Constructor.getDeclaredAnnotations(). 847 * This avoids the reflection classes to load the Annotation class until 848 * it is needed. 849 */ 850 private static final Annotation[] EMPTY_ANNOTATION_ARRAY = new Annotation[0]; 851 public static Annotation[] toArray(Map<Class<? extends Annotation>, Annotation> annotations) { 852 return annotations.values().toArray(EMPTY_ANNOTATION_ARRAY); 853 } 854 855 static Annotation[] getEmptyAnnotationArray() { return EMPTY_ANNOTATION_ARRAY; } 856 }