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