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