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