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