• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 {
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 
getAnnotation( Class<?> c, Class<A> annotationType)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      */
isInherited(Class<? extends Annotation> annotationType)94     private static boolean isInherited(Class<? extends Annotation> annotationType) {
95         return isDeclaredAnnotationPresent(annotationType, Inherited.class);
96     }
97 
getAnnotations(Class<?> c)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      */
isAnnotationPresent( Class<?> c, Class<? extends Annotation> annotationType)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      */
getDeclaredAnnotations(AnnotatedElement element)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      */
getDeclaredAnnotation( AnnotatedElement element, Class<A> annotationClass)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      */
isDeclaredAnnotationPresent( AnnotatedElement element, Class<? extends Annotation> annotationClass)178     public static boolean isDeclaredAnnotationPresent(
179             AnnotatedElement element, Class<? extends Annotation> annotationClass) {
180         return getAnnotation(element, annotationClass) != null;
181     }
182 
getAnnotation( AnnotatedElement element, Class<? extends Annotation> annotationClass)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      */
getAnnotationSetOffset(AnnotatedElement element)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      */
getDexClass(AnnotatedElement element)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      */
getParameterAnnotations(Class<?> declaringClass, int methodDexIndex)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 
getDefaultValue(Method method)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      */
getEnclosingClass(Class<?> c)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 
getEnclosingMethodOrConstructor(Class<?> c)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 
getMemberClasses(Class<?> c)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      */
getSignature(AnnotatedElement element)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      */
getExceptions(AnnotatedElement element)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 
getInnerClassFlags(Class<?> c, int defaultValue)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 
getInnerClassName(Class<?> c)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 
isAnonymousClass(Class<?> c)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 
getAnnotationReader( Dex dex, AnnotatedElement element, String annotationName, int expectedFieldCount)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      */
getOnlyAnnotationValue( Dex dex, AnnotatedElement element, String annotationName)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 
getAnnotationClass(Class<?> context, Dex dex, int typeIndex)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 
indexToMethod(Class<?> context, Dex dex, int methodIndex)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 
annotationSetToAnnotations(Class<?> context, int offset)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 
toAnnotationInstance(Class<?> context, Class<A> annotationClass, com.android.dex.Annotation annotation)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 
toAnnotationInstance(Class<?> context, Dex dex, Class<A> annotationClass, EncodedValueReader reader)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 
decodeValue(Class<?> context, Class<?> type, Dex dex, EncodedValueReader reader)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