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