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.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