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