Home | History | Annotate | Download | only in reflect
      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