Home | History | Annotate | Download | only in src
      1 /*
      2  * Copyright (C) 2008 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 import com.sun.javadoc.*;
     18 import com.sun.tools.doclets.*;
     19 import org.clearsilver.HDF;
     20 import org.clearsilver.CS;
     21 import java.util.ArrayList;
     22 import java.util.HashMap;
     23 import java.util.HashSet;
     24 
     25 public class Converter
     26 {
     27     private static RootDoc root;
     28 
     29     public static void makeInfo(RootDoc r)
     30     {
     31         root = r;
     32 
     33         int N, i;
     34 
     35         // create the objects
     36         ClassDoc[] classDocs = r.classes();
     37         N = classDocs.length;
     38         for (i=0; i<N; i++) {
     39             Converter.obtainClass(classDocs[i]);
     40         }
     41         ArrayList<ClassInfo> classesNeedingInit2 = new ArrayList<ClassInfo>();
     42         // fill in the fields that reference other classes
     43         while (mClassesNeedingInit.size() > 0) {
     44             i = mClassesNeedingInit.size()-1;
     45             ClassNeedingInit clni = mClassesNeedingInit.get(i);
     46             mClassesNeedingInit.remove(i);
     47 
     48             initClass(clni.c, clni.cl);
     49             classesNeedingInit2.add(clni.cl);
     50         }
     51         mClassesNeedingInit = null;
     52         for (ClassInfo cl: classesNeedingInit2) {
     53             cl.init2();
     54         }
     55 
     56         finishAnnotationValueInit();
     57 
     58         // fill in the "root" stuff
     59         mRootClasses = Converter.convertClasses(r.classes());
     60     }
     61 
     62     private static ClassInfo[] mRootClasses;
     63     public static ClassInfo[] rootClasses()
     64     {
     65         return mRootClasses;
     66     }
     67 
     68     public static ClassInfo[] allClasses() {
     69         return (ClassInfo[])mClasses.all();
     70     }
     71 
     72     private static void initClass(ClassDoc c, ClassInfo cl)
     73     {
     74         MethodDoc[] annotationElements;
     75         if (c instanceof AnnotationTypeDoc) {
     76             annotationElements = ((AnnotationTypeDoc)c).elements();
     77         } else {
     78             annotationElements = new MethodDoc[0];
     79         }
     80         cl.init(Converter.obtainType(c),
     81                 Converter.convertClasses(c.interfaces()),
     82                 Converter.convertTypes(c.interfaceTypes()),
     83                 Converter.convertClasses(c.innerClasses()),
     84                 Converter.convertMethods(c.constructors(false)),
     85                 Converter.convertMethods(c.methods(false)),
     86                 Converter.convertMethods(annotationElements),
     87                 Converter.convertFields(c.fields(false)),
     88                 Converter.convertFields(c.enumConstants()),
     89                 Converter.obtainPackage(c.containingPackage()),
     90                 Converter.obtainClass(c.containingClass()),
     91                 Converter.obtainClass(c.superclass()),
     92                 Converter.obtainType(c.superclassType()),
     93                 Converter.convertAnnotationInstances(c.annotations())
     94                 );
     95           cl.setHiddenMethods(Converter.getHiddenMethods(c.methods(false)));
     96           cl.setNonWrittenConstructors(Converter.convertNonWrittenConstructors(c.constructors(false)));
     97           cl.init3(Converter.convertTypes(c.typeParameters()), Converter.convertClasses(c.innerClasses(false)));
     98     }
     99 
    100     public static ClassInfo obtainClass(String className)
    101     {
    102         return Converter.obtainClass(root.classNamed(className));
    103     }
    104 
    105     public static PackageInfo obtainPackage(String packageName)
    106     {
    107         return Converter.obtainPackage(root.packageNamed(packageName));
    108     }
    109 
    110     private static TagInfo convertTag(Tag tag)
    111     {
    112         return new TextTagInfo(tag.name(), tag.kind(), tag.text(),
    113                                 Converter.convertSourcePosition(tag.position()));
    114     }
    115 
    116     private static ThrowsTagInfo convertThrowsTag(ThrowsTag tag,
    117                                                 ContainerInfo base)
    118     {
    119         return new ThrowsTagInfo(tag.name(), tag.text(), tag.kind(),
    120                               Converter.obtainClass(tag.exception()),
    121                               tag.exceptionComment(), base,
    122                               Converter.convertSourcePosition(tag.position()));
    123     }
    124 
    125     private static ParamTagInfo convertParamTag(ParamTag tag,
    126                                                 ContainerInfo base)
    127     {
    128         return new ParamTagInfo(tag.name(), tag.kind(), tag.text(),
    129                               tag.isTypeParameter(), tag.parameterComment(),
    130                               tag.parameterName(),
    131                               base,
    132                               Converter.convertSourcePosition(tag.position()));
    133     }
    134 
    135     private static SeeTagInfo convertSeeTag(SeeTag tag, ContainerInfo base)
    136     {
    137         return new SeeTagInfo(tag.name(), tag.kind(), tag.text(), base,
    138                               Converter.convertSourcePosition(tag.position()));
    139     }
    140 
    141     private static SourcePositionInfo convertSourcePosition(SourcePosition sp)
    142     {
    143         if (sp == null) {
    144             return null;
    145         }
    146         return new SourcePositionInfo(sp.file().toString(), sp.line(),
    147                                         sp.column());
    148     }
    149 
    150     public static TagInfo[] convertTags(Tag[] tags, ContainerInfo base)
    151     {
    152         int len = tags.length;
    153         TagInfo[] out = new TagInfo[len];
    154         for (int i=0; i<len; i++) {
    155             Tag t = tags[i];
    156             /*
    157             System.out.println("Tag name='" + t.name() + "' kind='"
    158                     + t.kind() + "'");
    159             */
    160             if (t instanceof SeeTag) {
    161                 out[i] = Converter.convertSeeTag((SeeTag)t, base);
    162             }
    163             else if (t instanceof ThrowsTag) {
    164                 out[i] = Converter.convertThrowsTag((ThrowsTag)t, base);
    165             }
    166             else if (t instanceof ParamTag) {
    167                 out[i] = Converter.convertParamTag((ParamTag)t, base);
    168             }
    169             else {
    170                 out[i] = Converter.convertTag(t);
    171             }
    172         }
    173         return out;
    174     }
    175 
    176     public static ClassInfo[] convertClasses(ClassDoc[] classes)
    177     {
    178         if (classes == null) return null;
    179         int N = classes.length;
    180         ClassInfo[] result = new ClassInfo[N];
    181         for (int i=0; i<N; i++) {
    182             result[i] = Converter.obtainClass(classes[i]);
    183         }
    184         return result;
    185     }
    186 
    187     private static ParameterInfo convertParameter(Parameter p, SourcePosition pos)
    188     {
    189         if (p == null) return null;
    190         ParameterInfo pi = new ParameterInfo(p.name(), p.typeName(),
    191                 Converter.obtainType(p.type()),
    192                 Converter.convertSourcePosition(pos));
    193         return pi;
    194     }
    195 
    196     private static ParameterInfo[] convertParameters(Parameter[] p, MemberDoc m)
    197     {
    198         SourcePosition pos = m.position();
    199         int len = p.length;
    200         ParameterInfo[] q = new ParameterInfo[len];
    201         for (int i=0; i<len; i++) {
    202             q[i] = Converter.convertParameter(p[i], pos);
    203         }
    204         return q;
    205     }
    206 
    207     private static TypeInfo[] convertTypes(Type[] p)
    208     {
    209         if (p == null) return null;
    210         int len = p.length;
    211         TypeInfo[] q = new TypeInfo[len];
    212         for (int i=0; i<len; i++) {
    213             q[i] = Converter.obtainType(p[i]);
    214         }
    215         return q;
    216     }
    217 
    218     private Converter()
    219     {
    220     }
    221 
    222     private static class ClassNeedingInit
    223     {
    224         ClassNeedingInit(ClassDoc c, ClassInfo cl)
    225         {
    226             this.c = c;
    227             this.cl = cl;
    228         }
    229         ClassDoc c;
    230         ClassInfo cl;
    231     };
    232     private static ArrayList<ClassNeedingInit> mClassesNeedingInit
    233                                             = new ArrayList<ClassNeedingInit>();
    234 
    235     static ClassInfo obtainClass(ClassDoc o)
    236     {
    237         return (ClassInfo)mClasses.obtain(o);
    238     }
    239     private static Cache mClasses = new Cache()
    240     {
    241         @Override
    242         protected Object make(Object o)
    243         {
    244             ClassDoc c = (ClassDoc)o;
    245             ClassInfo cl = new ClassInfo(
    246                     c,
    247                     c.getRawCommentText(),
    248                     Converter.convertSourcePosition(c.position()),
    249                     c.isPublic(),
    250                     c.isProtected(),
    251                     c.isPackagePrivate(),
    252                     c.isPrivate(),
    253                     c.isStatic(),
    254                     c.isInterface(),
    255                     c.isAbstract(),
    256                     c.isOrdinaryClass(),
    257                     c.isException(),
    258                     c.isError(),
    259                     c.isEnum(),
    260                     (c instanceof AnnotationTypeDoc),
    261                     c.isFinal(),
    262                     c.isIncluded(),
    263                     c.name(),
    264                     c.qualifiedName(),
    265                     c.qualifiedTypeName(),
    266                     c.isPrimitive());
    267             if (mClassesNeedingInit != null) {
    268                 mClassesNeedingInit.add(new ClassNeedingInit(c, cl));
    269             }
    270             return cl;
    271         }
    272         @Override
    273         protected void made(Object o, Object r)
    274         {
    275             if (mClassesNeedingInit == null) {
    276                 initClass((ClassDoc)o, (ClassInfo)r);
    277                 ((ClassInfo)r).init2();
    278             }
    279         }
    280         @Override
    281         ClassInfo[] all()
    282         {
    283             return (ClassInfo[])mCache.values().toArray(new ClassInfo[mCache.size()]);
    284         }
    285     };
    286 
    287     private static MethodInfo[] getHiddenMethods(MethodDoc[] methods){
    288       if (methods == null) return null;
    289       ArrayList<MethodInfo> out = new ArrayList<MethodInfo>();
    290       int N = methods.length;
    291       for (int i=0; i<N; i++) {
    292           MethodInfo m = Converter.obtainMethod(methods[i]);
    293           //System.out.println(m.toString() + ": ");
    294           //for (TypeInfo ti : m.getTypeParameters()){
    295             //  if (ti.asClassInfo() != null){
    296                 //System.out.println(" " +ti.asClassInfo().toString());
    297               //} else {
    298                 //System.out.println(" null");
    299               //}
    300             //}
    301           if (m.isHidden()) {
    302               out.add(m);
    303           }
    304       }
    305       return out.toArray(new MethodInfo[out.size()]);
    306     }
    307 
    308     /**
    309      * Convert MethodDoc[] into MethodInfo[].  Also filters according
    310      * to the -private, -public option, because the filtering doesn't seem
    311      * to be working in the ClassDoc.constructors(boolean) call.
    312      */
    313     private static MethodInfo[] convertMethods(MethodDoc[] methods)
    314     {
    315         if (methods == null) return null;
    316         ArrayList<MethodInfo> out = new ArrayList<MethodInfo>();
    317         int N = methods.length;
    318         for (int i=0; i<N; i++) {
    319             MethodInfo m = Converter.obtainMethod(methods[i]);
    320             //System.out.println(m.toString() + ": ");
    321             //for (TypeInfo ti : m.getTypeParameters()){
    322               //  if (ti.asClassInfo() != null){
    323                   //System.out.println(" " +ti.asClassInfo().toString());
    324                 //} else {
    325                   //System.out.println(" null");
    326                 //}
    327               //}
    328             if (m.checkLevel()) {
    329                 out.add(m);
    330             }
    331         }
    332         return out.toArray(new MethodInfo[out.size()]);
    333     }
    334 
    335     private static MethodInfo[] convertMethods(ConstructorDoc[] methods)
    336     {
    337         if (methods == null) return null;
    338         ArrayList<MethodInfo> out = new ArrayList<MethodInfo>();
    339         int N = methods.length;
    340         for (int i=0; i<N; i++) {
    341             MethodInfo m = Converter.obtainMethod(methods[i]);
    342             if (m.checkLevel()) {
    343                 out.add(m);
    344             }
    345         }
    346         return out.toArray(new MethodInfo[out.size()]);
    347     }
    348 
    349     private static MethodInfo[] convertNonWrittenConstructors(ConstructorDoc[] methods)
    350     {
    351         if (methods == null) return null;
    352         ArrayList<MethodInfo> out = new ArrayList<MethodInfo>();
    353         int N = methods.length;
    354         for (int i=0; i<N; i++) {
    355             MethodInfo m = Converter.obtainMethod(methods[i]);
    356             if (!m.checkLevel()) {
    357                 out.add(m);
    358             }
    359         }
    360         return out.toArray(new MethodInfo[out.size()]);
    361     }
    362 
    363     private static MethodInfo obtainMethod(MethodDoc o)
    364     {
    365         return (MethodInfo)mMethods.obtain(o);
    366     }
    367     private static MethodInfo obtainMethod(ConstructorDoc o)
    368     {
    369         return (MethodInfo)mMethods.obtain(o);
    370     }
    371     private static Cache mMethods = new Cache()
    372     {
    373         @Override
    374         protected Object make(Object o)
    375         {
    376             if (o instanceof AnnotationTypeElementDoc) {
    377                 AnnotationTypeElementDoc m = (AnnotationTypeElementDoc)o;
    378                 MethodInfo result = new MethodInfo(
    379                                 m.getRawCommentText(),
    380                                 Converter.convertTypes(m.typeParameters()),
    381                                 m.name(), m.signature(),
    382                                 Converter.obtainClass(m.containingClass()),
    383                                 Converter.obtainClass(m.containingClass()),
    384                                 m.isPublic(), m.isProtected(),
    385                                 m.isPackagePrivate(), m.isPrivate(),
    386                                 m.isFinal(), m.isStatic(), m.isSynthetic(),
    387                                 m.isAbstract(), m.isSynchronized(), m.isNative(), true,
    388                                 "annotationElement",
    389                                 m.flatSignature(),
    390                                 Converter.obtainMethod(m.overriddenMethod()),
    391                                 Converter.obtainType(m.returnType()),
    392                                 Converter.convertParameters(m.parameters(), m),
    393                                 Converter.convertClasses(m.thrownExceptions()),
    394                                 Converter.convertSourcePosition(m.position()),
    395                                 Converter.convertAnnotationInstances(m.annotations())
    396                             );
    397                 result.setVarargs(m.isVarArgs());
    398                 result.init(Converter.obtainAnnotationValue(m.defaultValue(), result));
    399                 return result;
    400             }
    401             else if (o instanceof MethodDoc) {
    402                 MethodDoc m = (MethodDoc)o;
    403                 MethodInfo result = new MethodInfo(
    404                                 m.getRawCommentText(),
    405                                 Converter.convertTypes(m.typeParameters()),
    406                                 m.name(), m.signature(),
    407                                 Converter.obtainClass(m.containingClass()),
    408                                 Converter.obtainClass(m.containingClass()),
    409                                 m.isPublic(), m.isProtected(),
    410                                 m.isPackagePrivate(), m.isPrivate(),
    411                                 m.isFinal(), m.isStatic(), m.isSynthetic(),
    412                                 m.isAbstract(), m.isSynchronized(), m.isNative(), false,
    413                                 "method",
    414                                 m.flatSignature(),
    415                                 Converter.obtainMethod(m.overriddenMethod()),
    416                                 Converter.obtainType(m.returnType()),
    417                                 Converter.convertParameters(m.parameters(), m),
    418                                 Converter.convertClasses(m.thrownExceptions()),
    419                                 Converter.convertSourcePosition(m.position()),
    420                                 Converter.convertAnnotationInstances(m.annotations())
    421                            );
    422                 result.setVarargs(m.isVarArgs());
    423                 result.init(null);
    424                 return result;
    425             }
    426             else {
    427                 ConstructorDoc m = (ConstructorDoc)o;
    428                 MethodInfo result = new MethodInfo(
    429                                 m.getRawCommentText(),
    430                                 Converter.convertTypes(m.typeParameters()),
    431                                 m.name(), m.signature(),
    432                                 Converter.obtainClass(m.containingClass()),
    433                                 Converter.obtainClass(m.containingClass()),
    434                                 m.isPublic(), m.isProtected(),
    435                                 m.isPackagePrivate(), m.isPrivate(),
    436                                 m.isFinal(), m.isStatic(), m.isSynthetic(),
    437                                 false, m.isSynchronized(), m.isNative(), false,
    438                                 "constructor",
    439                                 m.flatSignature(),
    440                                 null,
    441                                 null,
    442                                 Converter.convertParameters(m.parameters(), m),
    443                                 Converter.convertClasses(m.thrownExceptions()),
    444                                 Converter.convertSourcePosition(m.position()),
    445                                 Converter.convertAnnotationInstances(m.annotations())
    446                             );
    447                 result.setVarargs(m.isVarArgs());
    448                 result.init(null);
    449                 return result;
    450             }
    451         }
    452     };
    453 
    454 
    455     private static FieldInfo[] convertFields(FieldDoc[] fields)
    456     {
    457         if (fields == null) return null;
    458         ArrayList<FieldInfo> out = new ArrayList<FieldInfo>();
    459         int N = fields.length;
    460         for (int i=0; i<N; i++) {
    461             FieldInfo f = Converter.obtainField(fields[i]);
    462             if (f.checkLevel()) {
    463                 out.add(f);
    464             }
    465         }
    466         return out.toArray(new FieldInfo[out.size()]);
    467     }
    468 
    469     private static FieldInfo obtainField(FieldDoc o)
    470     {
    471         return (FieldInfo)mFields.obtain(o);
    472     }
    473     private static FieldInfo obtainField(ConstructorDoc o)
    474     {
    475         return (FieldInfo)mFields.obtain(o);
    476     }
    477     private static Cache mFields = new Cache()
    478     {
    479         @Override
    480         protected Object make(Object o)
    481         {
    482             FieldDoc f = (FieldDoc)o;
    483             return new FieldInfo(f.name(),
    484                             Converter.obtainClass(f.containingClass()),
    485                             Converter.obtainClass(f.containingClass()),
    486                             f.isPublic(), f.isProtected(),
    487                             f.isPackagePrivate(), f.isPrivate(),
    488                             f.isFinal(), f.isStatic(), f.isTransient(), f.isVolatile(),
    489                             f.isSynthetic(),
    490                             Converter.obtainType(f.type()),
    491                             f.getRawCommentText(), f.constantValue(),
    492                             Converter.convertSourcePosition(f.position()),
    493                             Converter.convertAnnotationInstances(f.annotations())
    494                         );
    495         }
    496     };
    497 
    498     private static PackageInfo obtainPackage(PackageDoc o)
    499     {
    500         return (PackageInfo)mPackagees.obtain(o);
    501     }
    502     private static Cache mPackagees = new Cache()
    503     {
    504         @Override
    505         protected Object make(Object o)
    506         {
    507             PackageDoc p = (PackageDoc)o;
    508             return new PackageInfo(p, p.name(),
    509                     Converter.convertSourcePosition(p.position()));
    510         }
    511     };
    512 
    513     private static TypeInfo obtainType(Type o)
    514     {
    515         return (TypeInfo)mTypes.obtain(o);
    516     }
    517     private static Cache mTypes = new Cache()
    518     {
    519        @Override
    520     protected Object make(Object o)
    521        {
    522            Type t = (Type)o;
    523            String simpleTypeName;
    524            if (t instanceof ClassDoc) {
    525                simpleTypeName = ((ClassDoc)t).name();
    526            } else {
    527                simpleTypeName = t.simpleTypeName();
    528            }
    529            TypeInfo ti = new TypeInfo(t.isPrimitive(), t.dimension(),
    530                    simpleTypeName, t.qualifiedTypeName(),
    531                    Converter.obtainClass(t.asClassDoc()));
    532            return ti;
    533        }
    534         @Override
    535         protected void made(Object o, Object r)
    536         {
    537             Type t = (Type)o;
    538             TypeInfo ti = (TypeInfo)r;
    539             if (t.asParameterizedType() != null) {
    540                 ti.setTypeArguments(Converter.convertTypes(
    541                             t.asParameterizedType().typeArguments()));
    542             }
    543             else if (t instanceof ClassDoc) {
    544                 ti.setTypeArguments(Converter.convertTypes(((ClassDoc)t).typeParameters()));
    545             }
    546             else if (t.asTypeVariable() != null) {
    547                 ti.setBounds(null, Converter.convertTypes((t.asTypeVariable().bounds())));
    548                 ti.setIsTypeVariable(true);
    549             }
    550             else if (t.asWildcardType() != null) {
    551                 ti.setIsWildcard(true);
    552                 ti.setBounds(Converter.convertTypes(t.asWildcardType().superBounds()),
    553                              Converter.convertTypes(t.asWildcardType().extendsBounds()));
    554             }
    555         }
    556         @Override
    557         protected Object keyFor(Object o)
    558         {
    559             Type t = (Type)o;
    560             String keyString = o.getClass().getName() + "/" + o.toString() + "/";
    561             if (t.asParameterizedType() != null){
    562               keyString += t.asParameterizedType().toString() +"/";
    563               if (t.asParameterizedType().typeArguments() != null){
    564               for(Type ty : t.asParameterizedType().typeArguments()){
    565                 keyString += ty.toString() + "/";
    566               }
    567               }
    568             }else{
    569               keyString += "NoParameterizedType//";
    570             }
    571             if (t.asTypeVariable() != null){
    572               keyString += t.asTypeVariable().toString() +"/";
    573               if (t.asTypeVariable().bounds() != null){
    574               for(Type ty : t.asTypeVariable().bounds()){
    575                 keyString += ty.toString() + "/";
    576               }
    577               }
    578             }else{
    579               keyString += "NoTypeVariable//";
    580             }
    581             if (t.asWildcardType() != null){
    582               keyString += t.asWildcardType().toString() +"/";
    583               if (t.asWildcardType().superBounds() != null){
    584               for(Type ty : t.asWildcardType().superBounds()){
    585                 keyString += ty.toString() + "/";
    586               }
    587               }
    588               if (t.asWildcardType().extendsBounds() != null){
    589                 for(Type ty : t.asWildcardType().extendsBounds()){
    590                   keyString += ty.toString() + "/";
    591                 }
    592                 }
    593             }else{
    594               keyString += "NoWildCardType//";
    595             }
    596 
    597 
    598 
    599             return keyString;
    600         }
    601     };
    602 
    603 
    604 
    605     private static MemberInfo obtainMember(MemberDoc o)
    606     {
    607         return (MemberInfo)mMembers.obtain(o);
    608     }
    609     private static Cache mMembers = new Cache()
    610     {
    611         @Override
    612         protected Object make(Object o)
    613         {
    614             if (o instanceof MethodDoc) {
    615                 return Converter.obtainMethod((MethodDoc)o);
    616             }
    617             else if (o instanceof ConstructorDoc) {
    618                 return Converter.obtainMethod((ConstructorDoc)o);
    619             }
    620             else if (o instanceof FieldDoc) {
    621                 return Converter.obtainField((FieldDoc)o);
    622             }
    623             else {
    624                 return null;
    625             }
    626         }
    627     };
    628 
    629     private static AnnotationInstanceInfo[] convertAnnotationInstances(AnnotationDesc[] orig)
    630     {
    631         int len = orig.length;
    632         AnnotationInstanceInfo[] out = new AnnotationInstanceInfo[len];
    633         for (int i=0; i<len; i++) {
    634             out[i] = Converter.obtainAnnotationInstance(orig[i]);
    635         }
    636         return out;
    637     }
    638 
    639 
    640     private static AnnotationInstanceInfo obtainAnnotationInstance(AnnotationDesc o)
    641     {
    642         return (AnnotationInstanceInfo)mAnnotationInstances.obtain(o);
    643     }
    644     private static Cache mAnnotationInstances = new Cache()
    645     {
    646         @Override
    647         protected Object make(Object o)
    648         {
    649             AnnotationDesc a = (AnnotationDesc)o;
    650             ClassInfo annotationType = Converter.obtainClass(a.annotationType());
    651             AnnotationDesc.ElementValuePair[] ev = a.elementValues();
    652             AnnotationValueInfo[] elementValues = new AnnotationValueInfo[ev.length];
    653             for (int i=0; i<ev.length; i++) {
    654                 elementValues[i] = obtainAnnotationValue(ev[i].value(),
    655                                             Converter.obtainMethod(ev[i].element()));
    656             }
    657             return new AnnotationInstanceInfo(annotationType, elementValues);
    658         }
    659     };
    660 
    661 
    662     private abstract static class Cache
    663     {
    664         void put(Object key, Object value)
    665         {
    666             mCache.put(key, value);
    667         }
    668         Object obtain(Object o)
    669         {
    670             if (o == null ) {
    671                 return null;
    672             }
    673             Object k = keyFor(o);
    674             Object r = mCache.get(k);
    675             if (r == null) {
    676                 r = make(o);
    677                 mCache.put(k, r);
    678                 made(o, r);
    679             }
    680             return r;
    681         }
    682         protected HashMap<Object,Object> mCache = new HashMap<Object,Object>();
    683         protected abstract Object make(Object o);
    684         protected void made(Object o, Object r)
    685         {
    686         }
    687         protected Object keyFor(Object o) { return o; }
    688         Object[] all() { return null; }
    689     }
    690 
    691     // annotation values
    692     private static HashMap<AnnotationValue,AnnotationValueInfo> mAnnotationValues = new HashMap();
    693     private static HashSet<AnnotationValue> mAnnotationValuesNeedingInit = new HashSet();
    694 
    695     private static AnnotationValueInfo obtainAnnotationValue(AnnotationValue o, MethodInfo element)
    696     {
    697         if (o == null) {
    698             return null;
    699         }
    700         AnnotationValueInfo v = mAnnotationValues.get(o);
    701         if (v != null) return v;
    702         v = new AnnotationValueInfo(element);
    703         mAnnotationValues.put(o, v);
    704         if (mAnnotationValuesNeedingInit != null) {
    705             mAnnotationValuesNeedingInit.add(o);
    706         } else {
    707             initAnnotationValue(o, v);
    708         }
    709         return v;
    710     }
    711 
    712     private static void initAnnotationValue(AnnotationValue o, AnnotationValueInfo v) {
    713         Object orig = o.value();
    714         Object converted;
    715         if (orig instanceof Type) {
    716             // class literal
    717             converted = Converter.obtainType((Type)orig);
    718         }
    719         else if (orig instanceof FieldDoc) {
    720             // enum constant
    721             converted = Converter.obtainField((FieldDoc)orig);
    722         }
    723         else if (orig instanceof AnnotationDesc) {
    724             // annotation instance
    725             converted = Converter.obtainAnnotationInstance((AnnotationDesc)orig);
    726         }
    727         else if (orig instanceof AnnotationValue[]) {
    728             AnnotationValue[] old = (AnnotationValue[])orig;
    729             AnnotationValueInfo[] array = new AnnotationValueInfo[old.length];
    730             for (int i=0; i<array.length; i++) {
    731                 array[i] = Converter.obtainAnnotationValue(old[i], null);
    732             }
    733             converted = array;
    734         }
    735         else {
    736             converted = orig;
    737         }
    738         v.init(converted);
    739     }
    740 
    741     private static void finishAnnotationValueInit()
    742     {
    743         int depth = 0;
    744         while (mAnnotationValuesNeedingInit.size() > 0) {
    745             HashSet<AnnotationValue> set = mAnnotationValuesNeedingInit;
    746             mAnnotationValuesNeedingInit = new HashSet();
    747             for (AnnotationValue o: set) {
    748                 AnnotationValueInfo v = mAnnotationValues.get(o);
    749                 initAnnotationValue(o, v);
    750             }
    751             depth++;
    752         }
    753         mAnnotationValuesNeedingInit = null;
    754     }
    755 }
    756