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