1 /* 2 * Copyright (C) 2011 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package libcore.reflect; 18 19 import com.android.dex.Dex; 20 import com.android.dex.EncodedValueReader; 21 import com.android.dex.FieldId; 22 import com.android.dex.MethodId; 23 import com.android.dex.ProtoId; 24 import com.android.dex.TypeList; 25 import java.lang.annotation.Annotation; 26 import java.lang.annotation.Inherited; 27 import java.lang.reflect.AccessibleObject; 28 import java.lang.reflect.AnnotatedElement; 29 import java.lang.reflect.Array; 30 import java.lang.reflect.Constructor; 31 import java.lang.reflect.Field; 32 import java.lang.reflect.Member; 33 import java.lang.reflect.Method; 34 import java.util.ArrayList; 35 import java.util.Arrays; 36 import java.util.Collection; 37 import java.util.Collections; 38 import java.util.HashMap; 39 import java.util.List; 40 import libcore.util.EmptyArray; 41 42 /** 43 * Look up annotations from a dex file. 44 */ 45 public final class AnnotationAccess { 46 private AnnotationAccess() { 47 } 48 49 /* 50 * Classes like arrays, primitives and proxies will not have a Dex file. 51 * Such classes never have annotations. 52 */ 53 54 private static final Class<?>[] NO_ARGUMENTS = null; 55 @SuppressWarnings("unused") 56 private static final byte VISIBILITY_BUILD = 0x00; 57 private static final byte VISIBILITY_RUNTIME = 0x01; 58 @SuppressWarnings("unused") 59 private static final byte VISIBILITY_SYSTEM = 0x02; 60 61 /* 62 * Class annotations. This includes declared class annotations plus 63 * annotations on the superclass that have @Inherited. 64 */ 65 66 public static <A extends java.lang.annotation.Annotation> A getAnnotation( 67 Class<?> c, Class<A> annotationType) { 68 if (annotationType == null) { 69 throw new NullPointerException("annotationType == null"); 70 } 71 72 A annotation = getDeclaredAnnotation(c, annotationType); 73 if (annotation != null) { 74 return annotation; 75 } 76 77 if (isInherited(annotationType)) { 78 for (Class<?> sup = c.getSuperclass(); sup != null; sup = sup.getSuperclass()) { 79 annotation = getDeclaredAnnotation(sup, annotationType); 80 if (annotation != null) { 81 return annotation; 82 } 83 } 84 } 85 86 return null; 87 } 88 89 /** 90 * Returns true if {@code annotationType} annotations on the superclass 91 * apply to subclasses that don't have another annotation of the same 92 * type. 93 */ 94 private static boolean isInherited(Class<? extends Annotation> annotationType) { 95 return isDeclaredAnnotationPresent(annotationType, Inherited.class); 96 } 97 98 public static Annotation[] getAnnotations(Class<?> c) { 99 /* 100 * We need to get the annotations declared on this class, plus the 101 * annotations from superclasses that have the "@Inherited" annotation 102 * set. We create a temporary map to use while we accumulate the 103 * annotations and convert it to an array at the end. 104 * 105 * It's possible to have duplicates when annotations are inherited. 106 * We use a Map to filter those out. 107 * 108 * HashMap might be overkill here. 109 */ 110 HashMap<Class<?>, Annotation> map = new HashMap<Class<?>, Annotation>(); 111 for (Annotation declaredAnnotation : getDeclaredAnnotations(c)) { 112 map.put(declaredAnnotation.annotationType(), declaredAnnotation); 113 } 114 for (Class<?> sup = c.getSuperclass(); sup != null; sup = sup.getSuperclass()) { 115 for (Annotation declaredAnnotation : getDeclaredAnnotations(sup)) { 116 Class<? extends Annotation> clazz = declaredAnnotation.annotationType(); 117 if (!map.containsKey(clazz) && isInherited(clazz)) { 118 map.put(clazz, declaredAnnotation); 119 } 120 } 121 } 122 123 /* convert annotation values from HashMap to array */ 124 Collection<Annotation> coll = map.values(); 125 return coll.toArray(new Annotation[coll.size()]); 126 } 127 128 /** 129 * Returns true if {@code c} is annotated by {@code annotationType}. 130 */ 131 public static boolean isAnnotationPresent( 132 Class<?> c, Class<? extends Annotation> annotationType) { 133 if (annotationType == null) { 134 throw new NullPointerException("annotationType == null"); 135 } 136 137 if (isDeclaredAnnotationPresent(c, annotationType)) { 138 return true; 139 } 140 141 if (isInherited(annotationType)) { 142 for (Class<?> sup = c.getSuperclass(); sup != null; sup = sup.getSuperclass()) { 143 if (isDeclaredAnnotationPresent(sup, annotationType)) { 144 return true; 145 } 146 } 147 } 148 149 return false; 150 } 151 152 /* 153 * Class, Field, Method, Constructor and Parameter annotations 154 */ 155 156 /** 157 * Returns the annotations on {@code element}. 158 */ 159 public static List<Annotation> getDeclaredAnnotations(AnnotatedElement element) { 160 int offset = getAnnotationSetOffset(element); 161 return annotationSetToAnnotations(getDexClass(element), offset); 162 } 163 164 /** 165 * Returns the annotation if it exists. 166 */ 167 public static <A extends Annotation> A getDeclaredAnnotation( 168 AnnotatedElement element, Class<A> annotationClass) { 169 com.android.dex.Annotation a = getAnnotation(element, annotationClass); 170 return a != null 171 ? toAnnotationInstance(getDexClass(element), annotationClass, a) 172 : null; 173 } 174 175 /** 176 * Returns true if the annotation exists. 177 */ 178 public static boolean isDeclaredAnnotationPresent( 179 AnnotatedElement element, Class<? extends Annotation> annotationClass) { 180 return getAnnotation(element, annotationClass) != null; 181 } 182 183 private static com.android.dex.Annotation getAnnotation( 184 AnnotatedElement element, Class<? extends Annotation> annotationClass) { 185 int annotationSetOffset = getAnnotationSetOffset(element); 186 if (annotationSetOffset == 0) { 187 return null; // no annotation 188 } 189 190 Class<?> dexClass = getDexClass(element); 191 Dex dex = dexClass.getDex(); 192 Dex.Section setIn = dex.open(annotationSetOffset); // annotation_set_item 193 String annotationInternalName = InternalNames.getInternalName(annotationClass); 194 for (int i = 0, size = setIn.readInt(); i < size; i++) { 195 int annotationOffset = setIn.readInt(); 196 Dex.Section annotationIn = dex.open(annotationOffset); // annotation_item 197 // The internal string name of the annotation is compared here and deliberately not 198 // the value of annotationClass.getTypeIndex(). The annotationClass may have been 199 // defined by a different dex file, which would make the indexes incomparable. 200 com.android.dex.Annotation candidate = annotationIn.readAnnotation(); 201 String candidateInternalName = dex.typeNames().get(candidate.getTypeIndex()); 202 if (candidateInternalName.equals(annotationInternalName)) { 203 return candidate; 204 } 205 } 206 207 return null; // This set doesn't contain the annotation. 208 } 209 210 /** 211 * @param element a class, a field, a method or a constructor. 212 */ 213 private static int getAnnotationSetOffset(AnnotatedElement element) { 214 Class<?> dexClass = getDexClass(element); 215 int directoryOffset = dexClass.getDexAnnotationDirectoryOffset(); 216 if (directoryOffset == 0) { 217 return 0; // nothing on this class has annotations 218 } 219 220 Dex.Section directoryIn = dexClass.getDex().open(directoryOffset); 221 int classSetOffset = directoryIn.readInt(); 222 if (element instanceof Class) { 223 return classSetOffset; 224 } 225 226 int fieldsSize = directoryIn.readInt(); 227 int methodsSize = directoryIn.readInt(); 228 directoryIn.readInt(); // parameters size 229 230 if (element instanceof Field) { 231 int fieldIndex = ((Field) element).getDexFieldIndex(); 232 for (int i = 0; i < fieldsSize; i++) { 233 int candidateFieldIndex = directoryIn.readInt(); 234 int annotationSetOffset = directoryIn.readInt(); 235 if (candidateFieldIndex == fieldIndex) { 236 return annotationSetOffset; 237 } 238 } 239 // if we were searching for a field then we missed 240 return 0; 241 } 242 243 // Skip through the fields without reading them and look for constructors or methods. 244 directoryIn.skip(8 * fieldsSize); 245 246 int methodIndex= element instanceof Method ? ((Method) element).getDexMethodIndex() 247 : ((Constructor<?>) element).getDexMethodIndex(); 248 for (int i = 0; i < methodsSize; i++) { 249 int candidateMethodIndex = directoryIn.readInt(); 250 int annotationSetOffset = directoryIn.readInt(); 251 if (candidateMethodIndex == methodIndex) { 252 return annotationSetOffset; 253 } 254 } 255 256 return 0; 257 } 258 259 /** 260 * Returns {@code element} if it is a class; and the class declaring 261 * {@code element} otherwise. The dex file of the returned class also 262 * defines {@code element}. 263 */ 264 private static Class<?> getDexClass(AnnotatedElement element) { 265 return element instanceof Class 266 ? ((Class<?>) element) 267 : ((Member) element).getDeclaringClass(); 268 } 269 270 /** 271 * Returns the parameter annotations on {@code member}. 272 */ 273 public static Annotation[][] getParameterAnnotations(Class<?> declaringClass, 274 int methodDexIndex) { 275 Dex dex = declaringClass.getDex(); 276 int protoIndex = dex.methodIds().get(methodDexIndex).getProtoIndex(); 277 ProtoId proto = dex.protoIds().get(protoIndex); 278 TypeList parametersList = dex.readTypeList(proto.getParametersOffset()); 279 short[] types = parametersList.getTypes(); 280 int typesCount = types.length; 281 282 int directoryOffset = declaringClass.getDexAnnotationDirectoryOffset(); 283 if (directoryOffset == 0) { 284 return new Annotation[typesCount][0]; // nothing on this class has annotations 285 } 286 287 Dex.Section directoryIn = dex.open(directoryOffset); 288 directoryIn.readInt(); // class annotations 289 int fieldsSize = directoryIn.readInt(); 290 int methodsSize = directoryIn.readInt(); 291 int parametersSize = directoryIn.readInt(); 292 293 for (int i = 0; i < fieldsSize; i++) { 294 directoryIn.readInt(); // field_index 295 directoryIn.readInt(); // annotation_set 296 } 297 298 for (int i = 0; i < methodsSize; i++) { 299 directoryIn.readInt(); // method_index 300 directoryIn.readInt(); // annotation_set 301 } 302 303 for (int i = 0; i < parametersSize; i++) { 304 int candidateMethodDexIndex = directoryIn.readInt(); 305 int annotationSetRefListOffset = directoryIn.readInt(); 306 if (candidateMethodDexIndex != methodDexIndex) { 307 continue; 308 } 309 310 Dex.Section refList = dex.open(annotationSetRefListOffset); 311 int parameterCount = refList.readInt(); 312 Annotation[][] result = new Annotation[parameterCount][]; 313 for (int p = 0; p < parameterCount; p++) { 314 int annotationSetOffset = refList.readInt(); 315 List<Annotation> annotations 316 = annotationSetToAnnotations(declaringClass, annotationSetOffset); 317 result[p] = annotations.toArray(new Annotation[annotations.size()]); 318 } 319 return result; 320 } 321 322 return new Annotation[typesCount][0]; 323 } 324 325 /* 326 * System annotations. 327 */ 328 329 public static Object getDefaultValue(Method method) { 330 /* 331 * Dex represents this with @AnnotationDefault on annotations that have 332 * default values: 333 * 334 * @AnnotationDefault(value=@Foo(a=7)) 335 * public @interface Foo { 336 * int a() default 7; 337 * int b(); 338 * } 339 */ 340 341 Class<?> annotationClass = method.getDeclaringClass(); 342 // All lookups of type and string indexes are within the Dex that declares the annotation so 343 // the indexes can be compared directly. 344 Dex dex = annotationClass.getDex(); 345 EncodedValueReader reader = getOnlyAnnotationValue( 346 dex, annotationClass, "Ldalvik/annotation/AnnotationDefault;"); 347 if (reader == null) { 348 return null; 349 } 350 351 int fieldCount = reader.readAnnotation(); 352 if (reader.getAnnotationType() != annotationClass.getDexTypeIndex()) { 353 throw new AssertionError("annotation value type != annotation class"); 354 } 355 356 int methodNameIndex = dex.findStringIndex(method.getName()); 357 for (int i = 0; i < fieldCount; i++) { 358 int candidateNameIndex = reader.readAnnotationName(); 359 if (candidateNameIndex == methodNameIndex) { 360 Class<?> returnType = method.getReturnType(); 361 return decodeValue(annotationClass, returnType, dex, reader); 362 } else { 363 reader.skipValue(); 364 } 365 } 366 367 return null; 368 } 369 370 /** 371 * Returns the class of which {@code c} is a direct member. If {@code c} is 372 * defined in a method or constructor, this is not transitive. 373 */ 374 public static Class<?> getEnclosingClass(Class<?> c) { 375 /* 376 * public class Bar { 377 * @EnclosingClass(value=Bar) 378 * public class Foo {} 379 * } 380 */ 381 Dex dex = c.getDex(); 382 EncodedValueReader reader = getOnlyAnnotationValue( 383 dex, c, "Ldalvik/annotation/EnclosingClass;"); 384 if (reader == null) { 385 return null; 386 } 387 return c.getDexCacheType(dex, reader.readType()); 388 } 389 390 public static AccessibleObject getEnclosingMethodOrConstructor(Class<?> c) { 391 /* 392 * public class Bar { 393 * public void quux(String s, int i) { 394 * @EnclosingMethod(value=Bar.quux(String,int)) 395 * class Foo {} 396 * } 397 * } 398 */ 399 Dex dex = c.getDex(); 400 EncodedValueReader reader = getOnlyAnnotationValue( 401 dex, c, "Ldalvik/annotation/EnclosingMethod;"); 402 if (reader == null) { 403 return null; 404 } 405 return indexToMethod(c, dex, reader.readMethod()); 406 } 407 408 public static Class<?>[] getMemberClasses(Class<?> c) { 409 /* 410 * @MemberClasses(value=[Bar, Baz]) 411 * public class Foo { 412 * class Bar {} 413 * class Baz {} 414 * } 415 */ 416 Dex dex = c.getDex(); 417 EncodedValueReader reader = getOnlyAnnotationValue( 418 dex, c, "Ldalvik/annotation/MemberClasses;"); 419 if (reader == null) { 420 return EmptyArray.CLASS; 421 } 422 return (Class[]) decodeValue(c, Class[].class, dex, reader); 423 } 424 425 /** 426 * @param element a class, a field, a method or a constructor. 427 */ 428 public static String getSignature(AnnotatedElement element) { 429 /* 430 * @Signature(value=["Ljava/util/List", "<", "Ljava/lang/String;", ">;"]) 431 * List<String> foo; 432 */ 433 Class<?> dexClass = getDexClass(element); 434 Dex dex = dexClass.getDex(); 435 EncodedValueReader reader = getOnlyAnnotationValue( 436 dex, element, "Ldalvik/annotation/Signature;"); 437 if (reader == null) { 438 return null; 439 } 440 String[] array = (String[]) decodeValue(dexClass, String[].class, dex, reader); 441 StringBuilder result = new StringBuilder(); 442 for (String s : array) { 443 result.append(s); 444 } 445 return result.toString(); 446 } 447 448 /** 449 * @param element a method or a constructor. 450 */ 451 public static Class<?>[] getExceptions(AnnotatedElement element) { 452 /* 453 * @Throws(value=[IOException.class]) 454 * void foo() throws IOException; 455 */ 456 Class<?> dexClass = getDexClass(element); 457 Dex dex = dexClass.getDex(); 458 EncodedValueReader reader = getOnlyAnnotationValue( 459 dex, element, "Ldalvik/annotation/Throws;"); 460 if (reader == null) { 461 return EmptyArray.CLASS; 462 } 463 return (Class<?>[]) decodeValue(dexClass, Class[].class, dex, reader); 464 } 465 466 public static int getInnerClassFlags(Class<?> c, int defaultValue) { 467 /* 468 * @InnerClass(accessFlags=0x01,name="Foo") 469 * class Foo {}; 470 */ 471 Dex dex = c.getDex(); 472 EncodedValueReader reader = getAnnotationReader( 473 dex, c, "Ldalvik/annotation/InnerClass;", 2); 474 if (reader == null) { 475 return defaultValue; 476 } 477 reader.readAnnotationName(); // accessFlags 478 return reader.readInt(); 479 } 480 481 public static String getInnerClassName(Class<?> c) { 482 /* 483 * @InnerClass(accessFlags=0x01,name="Foo") 484 * class Foo {}; 485 */ 486 Dex dex = c.getDex(); 487 EncodedValueReader reader = getAnnotationReader( 488 dex, c, "Ldalvik/annotation/InnerClass;", 2); 489 if (reader == null) { 490 return null; 491 } 492 reader.readAnnotationName(); // accessFlags 493 reader.readInt(); 494 reader.readAnnotationName(); // name 495 return reader.peek() == EncodedValueReader.ENCODED_NULL 496 ? null 497 : (String) decodeValue(c, String.class, dex, reader); 498 } 499 500 public static boolean isAnonymousClass(Class<?> c) { 501 /* 502 * @InnerClass(accessFlags=0x01,name="Foo") 503 * class Foo {}; 504 */ 505 Dex dex = c.getDex(); 506 EncodedValueReader reader = getAnnotationReader( 507 dex, c, "Ldalvik/annotation/InnerClass;", 2); 508 if (reader == null) { 509 return false; 510 } 511 reader.readAnnotationName(); // accessFlags 512 reader.readInt(); 513 reader.readAnnotationName(); // name 514 return reader.peek() == EncodedValueReader.ENCODED_NULL; 515 } 516 517 /* 518 * Dex support. 519 * 520 * Different classes come from different Dex files. This class is careful 521 * to guarantee that Dex-relative indices and encoded values are interpreted 522 * using the Dex that they were read from. Methods that use Dex-relative 523 * values accept that Dex as a parameter or the class from which that Dex 524 * was derived. 525 */ 526 527 private static EncodedValueReader getAnnotationReader( 528 Dex dex, AnnotatedElement element, String annotationName, int expectedFieldCount) { 529 int annotationSetOffset = getAnnotationSetOffset(element); 530 if (annotationSetOffset == 0) { 531 return null; // no annotations on the class 532 } 533 534 Dex.Section setIn = dex.open(annotationSetOffset); // annotation_set_item 535 com.android.dex.Annotation annotation = null; 536 // TODO: is it better to compute the index of the annotation name in the dex file and check 537 // indices below? 538 for (int i = 0, size = setIn.readInt(); i < size; i++) { 539 int annotationOffset = setIn.readInt(); 540 Dex.Section annotationIn = dex.open(annotationOffset); // annotation_item 541 com.android.dex.Annotation candidate = annotationIn.readAnnotation(); 542 String candidateAnnotationName = dex.typeNames().get(candidate.getTypeIndex()); 543 if (annotationName.equals(candidateAnnotationName)) { 544 annotation = candidate; 545 break; 546 } 547 } 548 if (annotation == null) { 549 return null; // no annotation 550 } 551 552 EncodedValueReader reader = annotation.getReader(); 553 int fieldCount = reader.readAnnotation(); 554 String readerAnnotationName = dex.typeNames().get(reader.getAnnotationType()); 555 if (!readerAnnotationName.equals(annotationName)) { 556 throw new AssertionError(); 557 } 558 if (fieldCount != expectedFieldCount) { 559 return null; // not the expected values on this annotation; give up 560 } 561 562 return reader; 563 } 564 565 /** 566 * Returns a reader ready to read the only value of the annotation on 567 * {@code element}, or null if that annotation doesn't exist. 568 */ 569 private static EncodedValueReader getOnlyAnnotationValue( 570 Dex dex, AnnotatedElement element, String annotationName) { 571 EncodedValueReader reader = getAnnotationReader(dex, element, annotationName, 1); 572 if (reader == null) { 573 return null; 574 } 575 reader.readAnnotationName(); // skip the name 576 return reader; 577 } 578 579 private static Class<? extends Annotation> getAnnotationClass(Class<?> context, Dex dex, 580 int typeIndex) { 581 try { 582 @SuppressWarnings("unchecked") // we do a runtime check 583 Class<? extends Annotation> result = 584 (Class<? extends Annotation>) context.getDexCacheType(dex, typeIndex); 585 if (!result.isAnnotation()) { 586 throw new IncompatibleClassChangeError("Expected annotation: " + result.getName()); 587 } 588 return result; 589 } catch (NoClassDefFoundError ncdfe) { 590 return null; 591 } 592 } 593 594 private static AccessibleObject indexToMethod(Class<?> context, Dex dex, int methodIndex) { 595 Class<?> declaringClass = 596 context.getDexCacheType(dex, dex.declaringClassIndexFromMethodIndex(methodIndex)); 597 String name = context.getDexCacheString(dex, dex.nameIndexFromMethodIndex(methodIndex)); 598 short[] types = dex.parameterTypeIndicesFromMethodIndex(methodIndex); 599 Class<?>[] parametersArray = new Class[types.length]; 600 for (int i = 0; i < types.length; i++) { 601 parametersArray[i] = context.getDexCacheType(dex, types[i]); 602 } 603 try { 604 return name.equals("<init>") 605 ? declaringClass.getDeclaredConstructor(parametersArray) 606 : declaringClass.getDeclaredMethod(name, parametersArray); 607 } catch (NoSuchMethodException e) { 608 throw new IncompatibleClassChangeError("Couldn't find " + declaringClass.getName() 609 + "." + name + Arrays.toString(parametersArray)); 610 } 611 } 612 613 private static List<Annotation> annotationSetToAnnotations(Class<?> context, int offset) { 614 if (offset == 0) { 615 return Collections.emptyList(); // no annotations in the set 616 } 617 618 Dex dex = context.getDex(); 619 Dex.Section setIn = dex.open(offset); // annotation_set_item 620 int size = setIn.readInt(); 621 List<Annotation> result = new ArrayList<Annotation>(size); 622 623 for (int i = 0; i < size; i++) { 624 int annotationOffset = setIn.readInt(); 625 Dex.Section annotationIn = dex.open(annotationOffset); // annotation_item 626 com.android.dex.Annotation annotation = annotationIn.readAnnotation(); 627 if (annotation.getVisibility() != VISIBILITY_RUNTIME) { 628 continue; 629 } 630 Class<? extends Annotation> annotationClass = 631 getAnnotationClass(context, dex, annotation.getTypeIndex()); 632 if (annotationClass != null) { 633 result.add(toAnnotationInstance(context, dex, annotationClass, annotation.getReader())); 634 } 635 } 636 return result; 637 } 638 639 private static <A extends Annotation> A toAnnotationInstance(Class<?> context, 640 Class<A> annotationClass, com.android.dex.Annotation annotation) { 641 return toAnnotationInstance(context, context.getDex(), annotationClass, 642 annotation.getReader()); 643 } 644 645 private static <A extends Annotation> A toAnnotationInstance(Class<?> context, Dex dex, 646 Class<A> annotationClass, EncodedValueReader reader) { 647 int fieldCount = reader.readAnnotation(); 648 if (annotationClass != context.getDexCacheType(dex, reader.getAnnotationType())) { 649 throw new AssertionError("annotation value type != return type"); 650 } 651 AnnotationMember[] members = new AnnotationMember[fieldCount]; 652 for (int i = 0; i < fieldCount; i++) { 653 int name = reader.readAnnotationName(); 654 String nameString = dex.strings().get(name); 655 Method method; 656 try { 657 method = annotationClass.getMethod(nameString, NO_ARGUMENTS); 658 } catch (NoSuchMethodException e) { 659 throw new IncompatibleClassChangeError( 660 "Couldn't find " + annotationClass.getName() + "." + nameString); 661 } 662 Class<?> returnType = method.getReturnType(); 663 Object value = decodeValue(context, returnType, dex, reader); 664 members[i] = new AnnotationMember(nameString, value, returnType, method); 665 } 666 return AnnotationFactory.createAnnotation(annotationClass, members); 667 } 668 669 private static Object decodeValue(Class<?> context, Class<?> type, 670 Dex dex, EncodedValueReader reader) { 671 if (type.isArray()) { 672 int size = reader.readArray(); 673 Class<?> componentType = type.getComponentType(); 674 Object array = Array.newInstance(componentType, size); 675 for (int i = 0; i < size; i++) { 676 Array.set(array, i, decodeValue(context, componentType, dex, reader)); 677 } 678 return array; 679 } else if (type.isEnum()) { 680 int fieldIndex = reader.readEnum(); 681 FieldId fieldId = dex.fieldIds().get(fieldIndex); 682 String fieldName = dex.strings().get(fieldId.getNameIndex()); 683 Field field; 684 try { 685 field = type.getDeclaredField(fieldName); 686 return field.get(null); 687 } catch (NoSuchFieldException e) { 688 NoSuchFieldError error = new NoSuchFieldError(); 689 error.initCause(e); 690 throw error; 691 } catch (IllegalAccessException e) { 692 IllegalAccessError error = new IllegalAccessError(); 693 error.initCause(e); 694 throw error; 695 } 696 } else if (type.isAnnotation()) { 697 @SuppressWarnings("unchecked") // Class.isAnnotation is the runtime check 698 Class<? extends Annotation> annotationClass = (Class<? extends Annotation>) type; 699 return toAnnotationInstance(context, dex, annotationClass, reader); 700 } else if (type == String.class) { 701 int index = reader.readString(); 702 return context.getDexCacheString(dex, index); 703 } else if (type == Class.class) { 704 int index = reader.readType(); 705 return context.getDexCacheType(dex, index); 706 } else if (type == byte.class) { 707 return reader.readByte(); 708 } else if (type == short.class) { 709 return reader.readShort(); 710 } else if (type == int.class) { 711 return reader.readInt(); 712 } else if (type == long.class) { 713 return reader.readLong(); 714 } else if (type == float.class) { 715 return reader.readFloat(); 716 } else if (type == double.class) { 717 return reader.readDouble(); 718 } else if (type == char.class) { 719 return reader.readChar(); 720 } else if (type == boolean.class) { 721 return reader.readBoolean(); 722 } else { 723 // is null legit? 724 throw new AssertionError("Unexpected annotation value type: " + type); 725 } 726 } 727 } 728