blob: 1bc3563ead37255dda3d1f3a2dd979aeddee6f03 [file] [log] [blame]
/*
* Copyright (C) 2010 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.google.doclava;
import com.sun.javadoc.AnnotationDesc;
import com.sun.javadoc.AnnotationTypeDoc;
import com.sun.javadoc.AnnotationTypeElementDoc;
import com.sun.javadoc.AnnotationValue;
import com.sun.javadoc.ClassDoc;
import com.sun.javadoc.ConstructorDoc;
import com.sun.javadoc.ExecutableMemberDoc;
import com.sun.javadoc.FieldDoc;
import com.sun.javadoc.MemberDoc;
import com.sun.javadoc.MethodDoc;
import com.sun.javadoc.PackageDoc;
import com.sun.javadoc.ParamTag;
import com.sun.javadoc.Parameter;
import com.sun.javadoc.RootDoc;
import com.sun.javadoc.SeeTag;
import com.sun.javadoc.SourcePosition;
import com.sun.javadoc.Tag;
import com.sun.javadoc.ThrowsTag;
import com.sun.javadoc.Type;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
public class Converter {
private static RootDoc root;
public static void makeInfo(RootDoc r) {
root = r;
// create the objects
ClassDoc[] classes = getClasses(r);
for (ClassDoc c : classes) {
Converter.obtainClass(c);
}
ArrayList<ClassInfo> classesNeedingInit2 = new ArrayList<ClassInfo>();
int i;
// fill in the fields that reference other classes
while (mClassesNeedingInit.size() > 0) {
i = mClassesNeedingInit.size() - 1;
ClassNeedingInit clni = mClassesNeedingInit.get(i);
mClassesNeedingInit.remove(i);
initClass(clni.c, clni.cl);
classesNeedingInit2.add(clni.cl);
}
mClassesNeedingInit = null;
for (ClassInfo cl : classesNeedingInit2) {
cl.init2();
}
finishAnnotationValueInit();
// fill in the "root" stuff
mRootClasses = Converter.convertClasses(classes);
}
private static ClassDoc[] getClasses(RootDoc r) {
ClassDoc[] classDocs = r.classes();
ArrayList<ClassDoc> filtered = new ArrayList<ClassDoc>(classDocs.length);
for (ClassDoc c : classDocs) {
if (c.position() != null) {
// Work around a javadoc bug in Java 7: We sometimes spuriously
// receive duplicate top level ClassDocs with null positions and no type
// information. Ignore them, since every ClassDoc must have a non null
// position.
filtered.add(c);
}
}
ClassDoc[] filteredArray = new ClassDoc[filtered.size()];
filtered.toArray(filteredArray);
return filteredArray;
}
private static ClassInfo[] mRootClasses;
public static ClassInfo[] rootClasses() {
return mRootClasses;
}
public static ClassInfo[] allClasses() {
return (ClassInfo[]) mClasses.all();
}
private static final MethodDoc[] EMPTY_METHOD_DOC = new MethodDoc[0];
private static void initClass(ClassDoc c, ClassInfo cl) {
MethodDoc[] annotationElements;
if (c instanceof AnnotationTypeDoc) {
annotationElements = ((AnnotationTypeDoc) c).elements();
} else {
annotationElements = EMPTY_METHOD_DOC;
}
cl.init(Converter.obtainType(c),
new ArrayList<ClassInfo>(Arrays.asList(Converter.convertClasses(c.interfaces()))),
new ArrayList<TypeInfo>(Arrays.asList(Converter.convertTypes(c.interfaceTypes()))),
new ArrayList<ClassInfo>(Arrays.asList(Converter.convertClasses(c.innerClasses()))),
new ArrayList<MethodInfo>(Arrays.asList(
Converter.convertMethods(c.constructors(false)))),
new ArrayList<MethodInfo>(Arrays.asList(Converter.convertMethods(c.methods(false)))),
new ArrayList<MethodInfo>(Arrays.asList(Converter.convertMethods(annotationElements))),
new ArrayList<FieldInfo>(Arrays.asList(Converter.convertFields(c.fields(false)))),
new ArrayList<FieldInfo>(Arrays.asList(Converter.convertFields(c.enumConstants()))),
Converter.obtainPackage(c.containingPackage()),
Converter.obtainClass(c.containingClass()),
Converter.obtainClass(c.superclass()), Converter.obtainType(c.superclassType()),
new ArrayList<AnnotationInstanceInfo>(Arrays.asList(
Converter.convertAnnotationInstances(c.annotations()))));
cl.setHiddenMethods(
new ArrayList<MethodInfo>(Arrays.asList(Converter.getHiddenMethods(c.methods(false)))));
cl.setRemovedMethods(
new ArrayList<MethodInfo>(Arrays.asList(Converter.getRemovedMethods(c.methods(false)))));
cl.setRemovedSelfMethods(
new ArrayList<MethodInfo>(Converter.convertAllMethods(c.methods(false))));
cl.setRemovedConstructors(
new ArrayList<MethodInfo>(Converter.convertAllMethods(c.constructors(false))));
cl.setRemovedSelfFields(
new ArrayList<FieldInfo>(Converter.convertAllFields(c.fields(false))));
cl.setRemovedEnumConstants(
new ArrayList<FieldInfo>(Converter.convertAllFields(c.enumConstants())));
cl.setNonWrittenConstructors(
new ArrayList<MethodInfo>(Arrays.asList(Converter.convertNonWrittenConstructors(
c.constructors(false)))));
cl.init3(
new ArrayList<TypeInfo>(Arrays.asList(Converter.convertTypes(c.typeParameters()))),
new ArrayList<ClassInfo>(Arrays.asList(
Converter.convertClasses(c.innerClasses(false)))));
}
public static ClassInfo obtainClass(String className) {
return Converter.obtainClass(root.classNamed(className));
}
public static PackageInfo obtainPackage(String packageName) {
return Converter.obtainPackage(root.packageNamed(packageName));
}
private static TagInfo convertTag(Tag tag) {
return new TextTagInfo(tag.name(), tag.kind(), tag.text(),
Converter.convertSourcePosition(tag.position()));
}
private static ThrowsTagInfo convertThrowsTag(ThrowsTag tag, ContainerInfo base) {
return new ThrowsTagInfo(tag.name(), tag.text(), tag.kind(), Converter.obtainClass(tag
.exception()), tag.exceptionComment(), base, Converter
.convertSourcePosition(tag.position()));
}
private static ParamTagInfo convertParamTag(ParamTag tag, ContainerInfo base) {
return new ParamTagInfo(tag.name(), tag.kind(), tag.text(), tag.isTypeParameter(), tag
.parameterComment(), tag.parameterName(), base, Converter.convertSourcePosition(tag
.position()));
}
private static SeeTagInfo convertSeeTag(SeeTag tag, ContainerInfo base) {
return new SeeTagInfo(tag.name(), tag.kind(), tag.text(), base, Converter
.convertSourcePosition(tag.position()));
}
private static SourcePositionInfo convertSourcePosition(SourcePosition sp) {
if (sp == null) {
return null;
}
return new SourcePositionInfo(sp.file().toString(), sp.line(), sp.column());
}
public static TagInfo[] convertTags(Tag[] tags, ContainerInfo base) {
int len = tags.length;
TagInfo[] out = TagInfo.getArray(len);
for (int i = 0; i < len; i++) {
Tag t = tags[i];
/*
* System.out.println("Tag name='" + t.name() + "' kind='" + t.kind() + "'");
*/
if (t instanceof SeeTag) {
out[i] = Converter.convertSeeTag((SeeTag) t, base);
} else if (t instanceof ThrowsTag) {
out[i] = Converter.convertThrowsTag((ThrowsTag) t, base);
} else if (t instanceof ParamTag) {
out[i] = Converter.convertParamTag((ParamTag) t, base);
} else {
out[i] = Converter.convertTag(t);
}
}
return out;
}
public static ClassInfo[] convertClasses(ClassDoc[] classes) {
if (classes == null) return null;
int N = classes.length;
ClassInfo[] result = new ClassInfo[N];
for (int i = 0; i < N; i++) {
result[i] = Converter.obtainClass(classes[i]);
}
return result;
}
private static ParameterInfo convertParameter(Parameter p, SourcePosition pos, boolean isVarArg) {
if (p == null) return null;
ParameterInfo pi =
new ParameterInfo(p.name(), p.typeName(), Converter.obtainType(p.type()), isVarArg,
Converter.convertSourcePosition(pos),
Arrays.asList(Converter.convertAnnotationInstances(p.annotations())));
return pi;
}
private static ParameterInfo[] convertParameters(Parameter[] p, ExecutableMemberDoc m) {
SourcePosition pos = m.position();
int len = p.length;
ParameterInfo[] q = new ParameterInfo[len];
for (int i = 0; i < len; i++) {
boolean isVarArg = (m.isVarArgs() && i == len - 1);
q[i] = Converter.convertParameter(p[i], pos, isVarArg);
}
return q;
}
private static TypeInfo[] convertTypes(Type[] p) {
if (p == null) return null;
int len = p.length;
TypeInfo[] q = new TypeInfo[len];
for (int i = 0; i < len; i++) {
q[i] = Converter.obtainType(p[i]);
}
return q;
}
private Converter() {}
private static class ClassNeedingInit {
ClassNeedingInit(ClassDoc c, ClassInfo cl) {
this.c = c;
this.cl = cl;
}
ClassDoc c;
ClassInfo cl;
}
private static ArrayList<ClassNeedingInit> mClassesNeedingInit =
new ArrayList<ClassNeedingInit>();
static ClassInfo obtainClass(ClassDoc o) {
return (ClassInfo) mClasses.obtain(o);
}
private static Cache mClasses = new Cache() {
@Override
protected Object make(Object o) {
ClassDoc c = (ClassDoc) o;
ClassInfo cl =
new ClassInfo(c, c.getRawCommentText(), Converter.convertSourcePosition(c.position()), c
.isPublic(), c.isProtected(), c.isPackagePrivate(), c.isPrivate(), c.isStatic(), c
.isInterface(), c.isAbstract(), c.isOrdinaryClass(), c.isException(), c.isError(), c
.isEnum(), (c instanceof AnnotationTypeDoc), c.isFinal(), c.isIncluded(), c.name(), c
.qualifiedName(), c.qualifiedTypeName(), c.isPrimitive());
if (mClassesNeedingInit != null) {
mClassesNeedingInit.add(new ClassNeedingInit(c, cl));
}
return cl;
}
@Override
protected void made(Object o, Object r) {
if (mClassesNeedingInit == null) {
initClass((ClassDoc) o, (ClassInfo) r);
((ClassInfo) r).init2();
}
}
@Override
ClassInfo[] all() {
return mCache.values().toArray(new ClassInfo[mCache.size()]);
}
};
private static MethodInfo[] getHiddenMethods(MethodDoc[] methods) {
if (methods == null) return null;
ArrayList<MethodInfo> hiddenMethods = new ArrayList<MethodInfo>();
for (MethodDoc method : methods) {
MethodInfo methodInfo = Converter.obtainMethod(method);
if (methodInfo.isHidden()) {
hiddenMethods.add(methodInfo);
}
}
return hiddenMethods.toArray(new MethodInfo[hiddenMethods.size()]);
}
// Gets the removed methods regardless of access levels
private static MethodInfo[] getRemovedMethods(MethodDoc[] methods) {
if (methods == null) return null;
ArrayList<MethodInfo> removedMethods = new ArrayList<MethodInfo>();
for (MethodDoc method : methods) {
MethodInfo methodInfo = Converter.obtainMethod(method);
if (methodInfo.isRemoved()) {
removedMethods.add(methodInfo);
}
}
return removedMethods.toArray(new MethodInfo[removedMethods.size()]);
}
/**
* Converts FieldDoc[] into List<FieldInfo>. No filtering is done.
*/
private static List<FieldInfo> convertAllFields(FieldDoc[] fields) {
if (fields == null) return null;
List<FieldInfo> allFields = new ArrayList<FieldInfo>();
for (FieldDoc field : fields) {
FieldInfo fieldInfo = Converter.obtainField(field);
allFields.add(fieldInfo);
}
return allFields;
}
/**
* Converts ExecutableMemberDoc[] into List<MethodInfo>. No filtering is done.
*/
private static List<MethodInfo> convertAllMethods(ExecutableMemberDoc[] methods) {
if (methods == null) return null;
List<MethodInfo> allMethods = new ArrayList<MethodInfo>();
for (ExecutableMemberDoc method : methods) {
MethodInfo methodInfo = Converter.obtainMethod(method);
allMethods.add(methodInfo);
}
return allMethods;
}
/**
* Convert MethodDoc[] or ConstructorDoc[] into MethodInfo[].
* Also filters according to the -private, -public option,
* because the filtering doesn't seem to be working in the ClassDoc.constructors(boolean) call.
*/
private static MethodInfo[] convertMethods(ExecutableMemberDoc[] methods) {
if (methods == null) return null;
List<MethodInfo> filteredMethods = new ArrayList<MethodInfo>();
for (ExecutableMemberDoc method : methods) {
MethodInfo methodInfo = Converter.obtainMethod(method);
if (methodInfo.checkLevel()) {
filteredMethods.add(methodInfo);
}
}
return filteredMethods.toArray(new MethodInfo[filteredMethods.size()]);
}
private static MethodInfo[] convertNonWrittenConstructors(ConstructorDoc[] methods) {
if (methods == null) return null;
ArrayList<MethodInfo> ctors = new ArrayList<MethodInfo>();
for (ConstructorDoc method : methods) {
MethodInfo methodInfo = Converter.obtainMethod(method);
if (!methodInfo.checkLevel()) {
ctors.add(methodInfo);
}
}
return ctors.toArray(new MethodInfo[ctors.size()]);
}
private static <E extends ExecutableMemberDoc> MethodInfo obtainMethod(E o) {
return (MethodInfo) mMethods.obtain(o);
}
private static Cache mMethods = new Cache() {
@Override
protected Object make(Object o) {
if (o instanceof AnnotationTypeElementDoc) {
AnnotationTypeElementDoc m = (AnnotationTypeElementDoc) o;
MethodInfo result =
new MethodInfo(m.getRawCommentText(),
new ArrayList<TypeInfo>(Arrays.asList(
Converter.convertTypes(m.typeParameters()))),
m.name(), m.signature(), Converter.obtainClass(m.containingClass()),
Converter.obtainClass(m.containingClass()), m.isPublic(), m.isProtected(), m
.isPackagePrivate(), m.isPrivate(), m.isFinal(), m.isStatic(), m.isSynthetic(),
m.isAbstract(), m.isSynchronized(), m.isNative(), m.isDefault(), true,
"annotationElement", m.flatSignature(),
Converter.obtainMethod(m.overriddenMethod()),
Converter.obtainType(m.returnType()),
new ArrayList<ParameterInfo>(Arrays.asList(
Converter.convertParameters(m.parameters(), m))),
new ArrayList<ClassInfo>(Arrays.asList(Converter.convertClasses(
m.thrownExceptions()))), Converter.convertSourcePosition(m.position()),
new ArrayList<AnnotationInstanceInfo>(Arrays.asList(
Converter.convertAnnotationInstances(m.annotations()))));
result.setVarargs(m.isVarArgs());
result.init(Converter.obtainAnnotationValue(m.defaultValue(), result));
return result;
} else if (o instanceof MethodDoc) {
MethodDoc m = (MethodDoc) o;
MethodInfo result =
new MethodInfo(m.getRawCommentText(),
new ArrayList<TypeInfo>(Arrays.asList(
Converter.convertTypes(m.typeParameters()))), m.name(), m.signature(),
Converter.obtainClass(m.containingClass()),
Converter.obtainClass(m.containingClass()), m.isPublic(), m.isProtected(),
m.isPackagePrivate(), m.isPrivate(), m.isFinal(), m.isStatic(), m.isSynthetic(),
m.isAbstract(), m.isSynchronized(), m.isNative(), m.isDefault(), false,
"method", m.flatSignature(), Converter.obtainMethod(m.overriddenMethod()),
Converter.obtainType(m.returnType()),
new ArrayList<ParameterInfo>(Arrays.asList(
Converter.convertParameters(m.parameters(), m))),
new ArrayList<ClassInfo>(Arrays.asList(
Converter.convertClasses(m.thrownExceptions()))),
Converter.convertSourcePosition(m.position()),
new ArrayList<AnnotationInstanceInfo>(Arrays.asList(
Converter.convertAnnotationInstances(m.annotations()))));
result.setVarargs(m.isVarArgs());
result.init(null);
return result;
} else {
ConstructorDoc m = (ConstructorDoc) o;
// Workaround for a JavaDoc behavior change introduced in OpenJDK 8 that breaks
// links in documentation and the content of API files like current.txt.
// http://b/18051133.
String name = m.name();
ClassDoc containingClass = m.containingClass();
if (containingClass.containingClass() != null) {
// This should detect the new behavior and be bypassed otherwise.
if (!name.contains(".")) {
// Constructors of inner classes do not contain the name of the enclosing class
// with OpenJDK 8. This simulates the old behavior:
name = containingClass.name();
}
}
// End of workaround.
MethodInfo result =
new MethodInfo(m.getRawCommentText(), new ArrayList<TypeInfo>(Arrays.asList(Converter.convertTypes(m.typeParameters()))),
name, m.signature(), Converter.obtainClass(m.containingClass()), Converter
.obtainClass(m.containingClass()), m.isPublic(), m.isProtected(), m
.isPackagePrivate(), m.isPrivate(), m.isFinal(), m.isStatic(), m.isSynthetic(),
false, m.isSynchronized(), m.isNative(), false/*isDefault*/, false, "constructor", m.flatSignature(),
null, null, new ArrayList<ParameterInfo>(Arrays.asList(Converter.convertParameters(m.parameters(), m))),
new ArrayList<ClassInfo>(Arrays.asList(Converter.convertClasses(m.thrownExceptions()))), Converter.convertSourcePosition(m
.position()), new ArrayList<AnnotationInstanceInfo>(Arrays.asList(Converter.convertAnnotationInstances(m.annotations()))));
result.setVarargs(m.isVarArgs());
result.init(null);
return result;
}
}
};
private static FieldInfo[] convertFields(FieldDoc[] fields) {
if (fields == null) return null;
ArrayList<FieldInfo> out = new ArrayList<FieldInfo>();
int N = fields.length;
for (int i = 0; i < N; i++) {
FieldInfo f = Converter.obtainField(fields[i]);
if (f.checkLevel()) {
out.add(f);
}
}
return out.toArray(new FieldInfo[out.size()]);
}
private static FieldInfo obtainField(FieldDoc o) {
return (FieldInfo) mFields.obtain(o);
}
private static FieldInfo obtainField(ConstructorDoc o) {
return (FieldInfo) mFields.obtain(o);
}
private static Cache mFields = new Cache() {
@Override
protected Object make(Object o) {
FieldDoc f = (FieldDoc) o;
return new FieldInfo(f.name(), Converter.obtainClass(f.containingClass()), Converter
.obtainClass(f.containingClass()), f.isPublic(), f.isProtected(), f.isPackagePrivate(), f
.isPrivate(), f.isFinal(), f.isStatic(), f.isTransient(), f.isVolatile(),
f.isSynthetic(), Converter.obtainType(f.type()), f.getRawCommentText(),
f.constantValue(), Converter.convertSourcePosition(f.position()),
new ArrayList<AnnotationInstanceInfo>(Arrays.asList(Converter
.convertAnnotationInstances(f.annotations()))));
}
};
private static PackageInfo obtainPackage(PackageDoc o) {
return (PackageInfo) mPackagees.obtain(o);
}
private static Cache mPackagees = new Cache() {
@Override
protected Object make(Object o) {
PackageDoc p = (PackageDoc) o;
return new PackageInfo(p, p.name(), Converter.convertSourcePosition(p.position()));
}
};
private static TypeInfo obtainType(Type o) {
return (TypeInfo) mTypes.obtain(o);
}
private static Cache mTypes = new Cache() {
@Override
protected Object make(Object o) {
Type t = (Type) o;
String simpleTypeName;
if (t instanceof ClassDoc) {
simpleTypeName = ((ClassDoc) t).name();
} else {
simpleTypeName = t.simpleTypeName();
}
TypeInfo ti =
new TypeInfo(t.isPrimitive(), t.dimension(), simpleTypeName, t.qualifiedTypeName(),
Converter.obtainClass(t.asClassDoc()));
return ti;
}
@Override
protected void made(Object o, Object r) {
Type t = (Type) o;
TypeInfo ti = (TypeInfo) r;
if (t.asParameterizedType() != null) {
ti.setTypeArguments(new ArrayList<TypeInfo>(Arrays.asList(Converter.convertTypes(t.asParameterizedType().typeArguments()))));
} else if (t instanceof ClassDoc) {
ti.setTypeArguments(new ArrayList<TypeInfo>(Arrays.asList(Converter.convertTypes(((ClassDoc) t).typeParameters()))));
} else if (t.asTypeVariable() != null) {
ti.setBounds(null, new ArrayList<TypeInfo>(Arrays.asList(Converter.convertTypes((t.asTypeVariable().bounds())))));
ti.setIsTypeVariable(true);
} else if (t.asWildcardType() != null) {
ti.setIsWildcard(true);
ti.setBounds(new ArrayList<TypeInfo>(Arrays.asList(Converter.convertTypes(t.asWildcardType().superBounds()))),
new ArrayList<TypeInfo>(Arrays.asList(Converter.convertTypes(t.asWildcardType().extendsBounds()))));
}
}
@Override
protected Object keyFor(Object o) {
Type t = (Type) o;
String keyString = o.getClass().getName() + "/" + o.toString() + "/";
if (t.asParameterizedType() != null) {
keyString += t.asParameterizedType().toString() + "/";
if (t.asParameterizedType().typeArguments() != null) {
for (Type ty : t.asParameterizedType().typeArguments()) {
keyString += ty.toString() + "/";
}
}
} else {
keyString += "NoParameterizedType//";
}
if (t.asTypeVariable() != null) {
keyString += t.asTypeVariable().toString() + "/";
if (t.asTypeVariable().bounds() != null) {
for (Type ty : t.asTypeVariable().bounds()) {
keyString += ty.toString() + "/";
}
}
} else {
keyString += "NoTypeVariable//";
}
if (t.asWildcardType() != null) {
keyString += t.asWildcardType().toString() + "/";
if (t.asWildcardType().superBounds() != null) {
for (Type ty : t.asWildcardType().superBounds()) {
keyString += ty.toString() + "/";
}
}
if (t.asWildcardType().extendsBounds() != null) {
for (Type ty : t.asWildcardType().extendsBounds()) {
keyString += ty.toString() + "/";
}
}
} else {
keyString += "NoWildCardType//";
}
return keyString;
}
};
public static TypeInfo obtainTypeFromString(String type) {
return (TypeInfo) mTypesFromString.obtain(type);
}
private static final Cache mTypesFromString = new Cache() {
@Override
protected Object make(Object o) {
String name = (String) o;
return new TypeInfo(name);
}
@Override
protected void made(Object o, Object r) {
}
@Override
protected Object keyFor(Object o) {
return o;
}
};
private static MemberInfo obtainMember(MemberDoc o) {
return (MemberInfo) mMembers.obtain(o);
}
private static Cache mMembers = new Cache() {
@Override
protected Object make(Object o) {
if (o instanceof MethodDoc) {
return Converter.obtainMethod((MethodDoc) o);
} else if (o instanceof ConstructorDoc) {
return Converter.obtainMethod((ConstructorDoc) o);
} else if (o instanceof FieldDoc) {
return Converter.obtainField((FieldDoc) o);
} else {
return null;
}
}
};
private static AnnotationInstanceInfo[] convertAnnotationInstances(AnnotationDesc[] orig) {
int len = orig.length;
AnnotationInstanceInfo[] out = new AnnotationInstanceInfo[len];
for (int i = 0; i < len; i++) {
out[i] = Converter.obtainAnnotationInstance(orig[i]);
}
return out;
}
private static AnnotationInstanceInfo obtainAnnotationInstance(AnnotationDesc o) {
return (AnnotationInstanceInfo) mAnnotationInstances.obtain(o);
}
private static Cache mAnnotationInstances = new Cache() {
@Override
protected Object make(Object o) {
AnnotationDesc a = (AnnotationDesc) o;
ClassInfo annotationType = Converter.obtainClass(a.annotationType());
AnnotationDesc.ElementValuePair[] ev = a.elementValues();
AnnotationValueInfo[] elementValues = new AnnotationValueInfo[ev.length];
for (int i = 0; i < ev.length; i++) {
elementValues[i] =
obtainAnnotationValue(ev[i].value(), Converter.obtainMethod(ev[i].element()));
}
return new AnnotationInstanceInfo(annotationType, elementValues);
}
};
private abstract static class Cache {
void put(Object key, Object value) {
mCache.put(key, value);
}
Object obtain(Object o) {
if (o == null) {
return null;
}
Object k = keyFor(o);
Object r = mCache.get(k);
if (r == null) {
r = make(o);
mCache.put(k, r);
made(o, r);
}
return r;
}
protected HashMap<Object, Object> mCache = new HashMap<Object, Object>();
protected abstract Object make(Object o);
protected void made(Object o, Object r) {}
protected Object keyFor(Object o) {
return o;
}
Object[] all() {
return null;
}
}
// annotation values
private static HashMap<AnnotationValue, AnnotationValueInfo> mAnnotationValues =
new HashMap<AnnotationValue, AnnotationValueInfo>();
private static HashSet<AnnotationValue> mAnnotationValuesNeedingInit =
new HashSet<AnnotationValue>();
private static AnnotationValueInfo obtainAnnotationValue(AnnotationValue o, MethodInfo element) {
if (o == null) {
return null;
}
AnnotationValueInfo v = mAnnotationValues.get(o);
if (v != null) return v;
v = new AnnotationValueInfo(element);
mAnnotationValues.put(o, v);
if (mAnnotationValuesNeedingInit != null) {
mAnnotationValuesNeedingInit.add(o);
} else {
initAnnotationValue(o, v);
}
return v;
}
private static void initAnnotationValue(AnnotationValue o, AnnotationValueInfo v) {
Object orig = o.value();
Object converted;
if (orig instanceof Type) {
// class literal
converted = Converter.obtainType((Type) orig);
} else if (orig instanceof FieldDoc) {
// enum constant
converted = Converter.obtainField((FieldDoc) orig);
} else if (orig instanceof AnnotationDesc) {
// annotation instance
converted = Converter.obtainAnnotationInstance((AnnotationDesc) orig);
} else if (orig instanceof AnnotationValue[]) {
AnnotationValue[] old = (AnnotationValue[]) orig;
ArrayList<AnnotationValueInfo> values = new ArrayList<AnnotationValueInfo>();
for (int i = 0; i < old.length; i++) {
values.add(Converter.obtainAnnotationValue(old[i], null));
}
converted = values;
} else {
converted = orig;
}
v.init(converted);
}
private static void finishAnnotationValueInit() {
int depth = 0;
while (mAnnotationValuesNeedingInit.size() > 0) {
HashSet<AnnotationValue> set = mAnnotationValuesNeedingInit;
mAnnotationValuesNeedingInit = new HashSet<AnnotationValue>();
for (AnnotationValue o : set) {
AnnotationValueInfo v = mAnnotationValues.get(o);
initAnnotationValue(o, v);
}
depth++;
}
mAnnotationValuesNeedingInit = null;
}
}