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