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 Arrays.asList(Converter.convertAnnotationInstances(p.annotations()))); 232 return pi; 233 } 234 convertParameters(Parameter[] p, ExecutableMemberDoc m)235 private static ParameterInfo[] convertParameters(Parameter[] p, ExecutableMemberDoc m) { 236 SourcePosition pos = m.position(); 237 int len = p.length; 238 ParameterInfo[] q = new ParameterInfo[len]; 239 for (int i = 0; i < len; i++) { 240 boolean isVarArg = (m.isVarArgs() && i == len - 1); 241 q[i] = Converter.convertParameter(p[i], pos, isVarArg); 242 } 243 return q; 244 } 245 convertTypes(Type[] p)246 private static TypeInfo[] convertTypes(Type[] p) { 247 if (p == null) return null; 248 int len = p.length; 249 TypeInfo[] q = new TypeInfo[len]; 250 for (int i = 0; i < len; i++) { 251 q[i] = Converter.obtainType(p[i]); 252 } 253 return q; 254 } 255 Converter()256 private Converter() {} 257 258 private static class ClassNeedingInit { ClassNeedingInit(ClassDoc c, ClassInfo cl)259 ClassNeedingInit(ClassDoc c, ClassInfo cl) { 260 this.c = c; 261 this.cl = cl; 262 } 263 264 ClassDoc c; 265 ClassInfo cl; 266 } 267 268 private static ArrayList<ClassNeedingInit> mClassesNeedingInit = 269 new ArrayList<ClassNeedingInit>(); 270 obtainClass(ClassDoc o)271 static ClassInfo obtainClass(ClassDoc o) { 272 return (ClassInfo) mClasses.obtain(o); 273 } 274 275 private static Cache mClasses = new Cache() { 276 @Override 277 protected Object make(Object o) { 278 ClassDoc c = (ClassDoc) o; 279 ClassInfo cl = 280 new ClassInfo(c, c.getRawCommentText(), Converter.convertSourcePosition(c.position()), c 281 .isPublic(), c.isProtected(), c.isPackagePrivate(), c.isPrivate(), c.isStatic(), c 282 .isInterface(), c.isAbstract(), c.isOrdinaryClass(), c.isException(), c.isError(), c 283 .isEnum(), (c instanceof AnnotationTypeDoc), c.isFinal(), c.isIncluded(), c.name(), c 284 .qualifiedName(), c.qualifiedTypeName(), c.isPrimitive()); 285 if (mClassesNeedingInit != null) { 286 mClassesNeedingInit.add(new ClassNeedingInit(c, cl)); 287 } 288 return cl; 289 } 290 291 @Override 292 protected void made(Object o, Object r) { 293 if (mClassesNeedingInit == null) { 294 initClass((ClassDoc) o, (ClassInfo) r); 295 ((ClassInfo) r).init2(); 296 } 297 } 298 299 @Override 300 ClassInfo[] all() { 301 return mCache.values().toArray(new ClassInfo[mCache.size()]); 302 } 303 }; 304 getHiddenMethods(MethodDoc[] methods)305 private static MethodInfo[] getHiddenMethods(MethodDoc[] methods) { 306 if (methods == null) return null; 307 ArrayList<MethodInfo> hiddenMethods = new ArrayList<MethodInfo>(); 308 for (MethodDoc method : methods) { 309 MethodInfo methodInfo = Converter.obtainMethod(method); 310 if (methodInfo.isHidden()) { 311 hiddenMethods.add(methodInfo); 312 } 313 } 314 315 return hiddenMethods.toArray(new MethodInfo[hiddenMethods.size()]); 316 } 317 318 // Gets the removed methods regardless of access levels getRemovedMethods(MethodDoc[] methods)319 private static MethodInfo[] getRemovedMethods(MethodDoc[] methods) { 320 if (methods == null) return null; 321 ArrayList<MethodInfo> removedMethods = new ArrayList<MethodInfo>(); 322 for (MethodDoc method : methods) { 323 MethodInfo methodInfo = Converter.obtainMethod(method); 324 if (methodInfo.isRemoved()) { 325 removedMethods.add(methodInfo); 326 } 327 } 328 329 return removedMethods.toArray(new MethodInfo[removedMethods.size()]); 330 } 331 332 /** 333 * Converts FieldDoc[] into List<FieldInfo>. No filtering is done. 334 */ convertAllFields(FieldDoc[] fields)335 private static List<FieldInfo> convertAllFields(FieldDoc[] fields) { 336 if (fields == null) return null; 337 List<FieldInfo> allFields = new ArrayList<FieldInfo>(); 338 339 for (FieldDoc field : fields) { 340 FieldInfo fieldInfo = Converter.obtainField(field); 341 allFields.add(fieldInfo); 342 } 343 344 return allFields; 345 } 346 347 /** 348 * Converts ExecutableMemberDoc[] into List<MethodInfo>. No filtering is done. 349 */ convertAllMethods(ExecutableMemberDoc[] methods)350 private static List<MethodInfo> convertAllMethods(ExecutableMemberDoc[] methods) { 351 if (methods == null) return null; 352 List<MethodInfo> allMethods = new ArrayList<MethodInfo>(); 353 for (ExecutableMemberDoc method : methods) { 354 MethodInfo methodInfo = Converter.obtainMethod(method); 355 allMethods.add(methodInfo); 356 } 357 return allMethods; 358 } 359 360 /** 361 * Convert MethodDoc[] or ConstructorDoc[] into MethodInfo[]. 362 * Also filters according to the -private, -public option, 363 * because the filtering doesn't seem to be working in the ClassDoc.constructors(boolean) call. 364 */ convertMethods(ExecutableMemberDoc[] methods)365 private static MethodInfo[] convertMethods(ExecutableMemberDoc[] methods) { 366 if (methods == null) return null; 367 List<MethodInfo> filteredMethods = new ArrayList<MethodInfo>(); 368 for (ExecutableMemberDoc method : methods) { 369 MethodInfo methodInfo = Converter.obtainMethod(method); 370 if (methodInfo.checkLevel()) { 371 filteredMethods.add(methodInfo); 372 } 373 } 374 375 return filteredMethods.toArray(new MethodInfo[filteredMethods.size()]); 376 } 377 convertNonWrittenConstructors(ConstructorDoc[] methods)378 private static MethodInfo[] convertNonWrittenConstructors(ConstructorDoc[] methods) { 379 if (methods == null) return null; 380 ArrayList<MethodInfo> ctors = new ArrayList<MethodInfo>(); 381 for (ConstructorDoc method : methods) { 382 MethodInfo methodInfo = Converter.obtainMethod(method); 383 if (!methodInfo.checkLevel()) { 384 ctors.add(methodInfo); 385 } 386 } 387 388 return ctors.toArray(new MethodInfo[ctors.size()]); 389 } 390 obtainMethod(E o)391 private static <E extends ExecutableMemberDoc> MethodInfo obtainMethod(E o) { 392 return (MethodInfo) mMethods.obtain(o); 393 } 394 395 private static Cache mMethods = new Cache() { 396 @Override 397 protected Object make(Object o) { 398 if (o instanceof AnnotationTypeElementDoc) { 399 AnnotationTypeElementDoc m = (AnnotationTypeElementDoc) o; 400 MethodInfo result = 401 new MethodInfo(m.getRawCommentText(), 402 new ArrayList<TypeInfo>(Arrays.asList( 403 Converter.convertTypes(m.typeParameters()))), 404 m.name(), m.signature(), Converter.obtainClass(m.containingClass()), 405 Converter.obtainClass(m.containingClass()), m.isPublic(), m.isProtected(), m 406 .isPackagePrivate(), m.isPrivate(), m.isFinal(), m.isStatic(), m.isSynthetic(), 407 m.isAbstract(), m.isSynchronized(), m.isNative(), m.isDefault(), true, 408 "annotationElement", m.flatSignature(), 409 Converter.obtainMethod(m.overriddenMethod()), 410 Converter.obtainType(m.returnType()), 411 new ArrayList<ParameterInfo>(Arrays.asList( 412 Converter.convertParameters(m.parameters(), m))), 413 new ArrayList<ClassInfo>(Arrays.asList(Converter.convertClasses( 414 m.thrownExceptions()))), Converter.convertSourcePosition(m.position()), 415 new ArrayList<AnnotationInstanceInfo>(Arrays.asList( 416 Converter.convertAnnotationInstances(m.annotations())))); 417 result.setVarargs(m.isVarArgs()); 418 result.init(Converter.obtainAnnotationValue(m.defaultValue(), result)); 419 return result; 420 } else if (o instanceof MethodDoc) { 421 MethodDoc m = (MethodDoc) o; 422 MethodInfo result = 423 new MethodInfo(m.getRawCommentText(), 424 new ArrayList<TypeInfo>(Arrays.asList( 425 Converter.convertTypes(m.typeParameters()))), m.name(), m.signature(), 426 Converter.obtainClass(m.containingClass()), 427 Converter.obtainClass(m.containingClass()), m.isPublic(), m.isProtected(), 428 m.isPackagePrivate(), m.isPrivate(), m.isFinal(), m.isStatic(), m.isSynthetic(), 429 m.isAbstract(), m.isSynchronized(), m.isNative(), m.isDefault(), false, 430 "method", m.flatSignature(), Converter.obtainMethod(m.overriddenMethod()), 431 Converter.obtainType(m.returnType()), 432 new ArrayList<ParameterInfo>(Arrays.asList( 433 Converter.convertParameters(m.parameters(), m))), 434 new ArrayList<ClassInfo>(Arrays.asList( 435 Converter.convertClasses(m.thrownExceptions()))), 436 Converter.convertSourcePosition(m.position()), 437 new ArrayList<AnnotationInstanceInfo>(Arrays.asList( 438 Converter.convertAnnotationInstances(m.annotations())))); 439 result.setVarargs(m.isVarArgs()); 440 result.init(null); 441 return result; 442 } else { 443 ConstructorDoc m = (ConstructorDoc) o; 444 // Workaround for a JavaDoc behavior change introduced in OpenJDK 8 that breaks 445 // links in documentation and the content of API files like current.txt. 446 // http://b/18051133. 447 String name = m.name(); 448 ClassDoc containingClass = m.containingClass(); 449 if (containingClass.containingClass() != null) { 450 // This should detect the new behavior and be bypassed otherwise. 451 if (!name.contains(".")) { 452 // Constructors of inner classes do not contain the name of the enclosing class 453 // with OpenJDK 8. This simulates the old behavior: 454 name = containingClass.name(); 455 } 456 } 457 // End of workaround. 458 MethodInfo result = 459 new MethodInfo(m.getRawCommentText(), new ArrayList<TypeInfo>(Arrays.asList(Converter.convertTypes(m.typeParameters()))), 460 name, m.signature(), Converter.obtainClass(m.containingClass()), Converter 461 .obtainClass(m.containingClass()), m.isPublic(), m.isProtected(), m 462 .isPackagePrivate(), m.isPrivate(), m.isFinal(), m.isStatic(), m.isSynthetic(), 463 false, m.isSynchronized(), m.isNative(), false/*isDefault*/, false, "constructor", m.flatSignature(), 464 null, null, new ArrayList<ParameterInfo>(Arrays.asList(Converter.convertParameters(m.parameters(), m))), 465 new ArrayList<ClassInfo>(Arrays.asList(Converter.convertClasses(m.thrownExceptions()))), Converter.convertSourcePosition(m 466 .position()), new ArrayList<AnnotationInstanceInfo>(Arrays.asList(Converter.convertAnnotationInstances(m.annotations())))); 467 result.setVarargs(m.isVarArgs()); 468 result.init(null); 469 return result; 470 } 471 } 472 }; 473 474 convertFields(FieldDoc[] fields)475 private static FieldInfo[] convertFields(FieldDoc[] fields) { 476 if (fields == null) return null; 477 ArrayList<FieldInfo> out = new ArrayList<FieldInfo>(); 478 int N = fields.length; 479 for (int i = 0; i < N; i++) { 480 FieldInfo f = Converter.obtainField(fields[i]); 481 if (f.checkLevel()) { 482 out.add(f); 483 } 484 } 485 return out.toArray(new FieldInfo[out.size()]); 486 } 487 obtainField(FieldDoc o)488 private static FieldInfo obtainField(FieldDoc o) { 489 return (FieldInfo) mFields.obtain(o); 490 } 491 obtainField(ConstructorDoc o)492 private static FieldInfo obtainField(ConstructorDoc o) { 493 return (FieldInfo) mFields.obtain(o); 494 } 495 496 private static Cache mFields = new Cache() { 497 @Override 498 protected Object make(Object o) { 499 FieldDoc f = (FieldDoc) o; 500 return new FieldInfo(f.name(), Converter.obtainClass(f.containingClass()), Converter 501 .obtainClass(f.containingClass()), f.isPublic(), f.isProtected(), f.isPackagePrivate(), f 502 .isPrivate(), f.isFinal(), f.isStatic(), f.isTransient(), f.isVolatile(), 503 f.isSynthetic(), Converter.obtainType(f.type()), f.getRawCommentText(), 504 f.constantValue(), Converter.convertSourcePosition(f.position()), 505 new ArrayList<AnnotationInstanceInfo>(Arrays.asList(Converter 506 .convertAnnotationInstances(f.annotations())))); 507 } 508 }; 509 obtainPackage(PackageDoc o)510 private static PackageInfo obtainPackage(PackageDoc o) { 511 return (PackageInfo) mPackagees.obtain(o); 512 } 513 514 private static Cache mPackagees = new Cache() { 515 @Override 516 protected Object make(Object o) { 517 PackageDoc p = (PackageDoc) o; 518 return new PackageInfo(p, p.name(), Converter.convertSourcePosition(p.position())); 519 } 520 }; 521 obtainType(Type o)522 private static TypeInfo obtainType(Type o) { 523 return (TypeInfo) mTypes.obtain(o); 524 } 525 526 private static Cache mTypes = new Cache() { 527 @Override 528 protected Object make(Object o) { 529 Type t = (Type) o; 530 String simpleTypeName; 531 if (t instanceof ClassDoc) { 532 simpleTypeName = ((ClassDoc) t).name(); 533 } else { 534 simpleTypeName = t.simpleTypeName(); 535 } 536 TypeInfo ti = 537 new TypeInfo(t.isPrimitive(), t.dimension(), simpleTypeName, t.qualifiedTypeName(), 538 Converter.obtainClass(t.asClassDoc())); 539 return ti; 540 } 541 542 @Override 543 protected void made(Object o, Object r) { 544 Type t = (Type) o; 545 TypeInfo ti = (TypeInfo) r; 546 if (t.asParameterizedType() != null) { 547 ti.setTypeArguments(new ArrayList<TypeInfo>(Arrays.asList(Converter.convertTypes(t.asParameterizedType().typeArguments())))); 548 } else if (t instanceof ClassDoc) { 549 ti.setTypeArguments(new ArrayList<TypeInfo>(Arrays.asList(Converter.convertTypes(((ClassDoc) t).typeParameters())))); 550 } else if (t.asTypeVariable() != null) { 551 ti.setBounds(null, new ArrayList<TypeInfo>(Arrays.asList(Converter.convertTypes((t.asTypeVariable().bounds()))))); 552 ti.setIsTypeVariable(true); 553 } else if (t.asWildcardType() != null) { 554 ti.setIsWildcard(true); 555 ti.setBounds(new ArrayList<TypeInfo>(Arrays.asList(Converter.convertTypes(t.asWildcardType().superBounds()))), 556 new ArrayList<TypeInfo>(Arrays.asList(Converter.convertTypes(t.asWildcardType().extendsBounds())))); 557 } 558 } 559 560 @Override 561 protected Object keyFor(Object o) { 562 Type t = (Type) o; 563 String keyString = o.getClass().getName() + "/" + o.toString() + "/"; 564 if (t.asParameterizedType() != null) { 565 keyString += t.asParameterizedType().toString() + "/"; 566 if (t.asParameterizedType().typeArguments() != null) { 567 for (Type ty : t.asParameterizedType().typeArguments()) { 568 keyString += ty.toString() + "/"; 569 } 570 } 571 } else { 572 keyString += "NoParameterizedType//"; 573 } 574 if (t.asTypeVariable() != null) { 575 keyString += t.asTypeVariable().toString() + "/"; 576 if (t.asTypeVariable().bounds() != null) { 577 for (Type ty : t.asTypeVariable().bounds()) { 578 keyString += ty.toString() + "/"; 579 } 580 } 581 } else { 582 keyString += "NoTypeVariable//"; 583 } 584 if (t.asWildcardType() != null) { 585 keyString += t.asWildcardType().toString() + "/"; 586 if (t.asWildcardType().superBounds() != null) { 587 for (Type ty : t.asWildcardType().superBounds()) { 588 keyString += ty.toString() + "/"; 589 } 590 } 591 if (t.asWildcardType().extendsBounds() != null) { 592 for (Type ty : t.asWildcardType().extendsBounds()) { 593 keyString += ty.toString() + "/"; 594 } 595 } 596 } else { 597 keyString += "NoWildCardType//"; 598 } 599 600 return keyString; 601 } 602 }; 603 obtainTypeFromString(String type)604 public static TypeInfo obtainTypeFromString(String type) { 605 return (TypeInfo) mTypesFromString.obtain(type); 606 } 607 608 private static final Cache mTypesFromString = new Cache() { 609 @Override 610 protected Object make(Object o) { 611 String name = (String) o; 612 return new TypeInfo(name); 613 } 614 615 @Override 616 protected void made(Object o, Object r) { 617 618 } 619 620 @Override 621 protected Object keyFor(Object o) { 622 return o; 623 } 624 }; 625 obtainMember(MemberDoc o)626 private static MemberInfo obtainMember(MemberDoc o) { 627 return (MemberInfo) mMembers.obtain(o); 628 } 629 630 private static Cache mMembers = new Cache() { 631 @Override 632 protected Object make(Object o) { 633 if (o instanceof MethodDoc) { 634 return Converter.obtainMethod((MethodDoc) o); 635 } else if (o instanceof ConstructorDoc) { 636 return Converter.obtainMethod((ConstructorDoc) o); 637 } else if (o instanceof FieldDoc) { 638 return Converter.obtainField((FieldDoc) o); 639 } else { 640 return null; 641 } 642 } 643 }; 644 convertAnnotationInstances(AnnotationDesc[] orig)645 private static AnnotationInstanceInfo[] convertAnnotationInstances(AnnotationDesc[] orig) { 646 int len = orig.length; 647 AnnotationInstanceInfo[] out = new AnnotationInstanceInfo[len]; 648 for (int i = 0; i < len; i++) { 649 out[i] = Converter.obtainAnnotationInstance(orig[i]); 650 } 651 return out; 652 } 653 654 obtainAnnotationInstance(AnnotationDesc o)655 private static AnnotationInstanceInfo obtainAnnotationInstance(AnnotationDesc o) { 656 return (AnnotationInstanceInfo) mAnnotationInstances.obtain(o); 657 } 658 659 private static Cache mAnnotationInstances = new Cache() { 660 @Override 661 protected Object make(Object o) { 662 AnnotationDesc a = (AnnotationDesc) o; 663 ClassInfo annotationType = Converter.obtainClass(a.annotationType()); 664 AnnotationDesc.ElementValuePair[] ev = a.elementValues(); 665 AnnotationValueInfo[] elementValues = new AnnotationValueInfo[ev.length]; 666 for (int i = 0; i < ev.length; i++) { 667 elementValues[i] = 668 obtainAnnotationValue(ev[i].value(), Converter.obtainMethod(ev[i].element())); 669 } 670 return new AnnotationInstanceInfo(annotationType, elementValues); 671 } 672 }; 673 674 675 private abstract static class Cache { put(Object key, Object value)676 void put(Object key, Object value) { 677 mCache.put(key, value); 678 } 679 obtain(Object o)680 Object obtain(Object o) { 681 if (o == null) { 682 return null; 683 } 684 Object k = keyFor(o); 685 Object r = mCache.get(k); 686 if (r == null) { 687 r = make(o); 688 mCache.put(k, r); 689 made(o, r); 690 } 691 return r; 692 } 693 694 protected HashMap<Object, Object> mCache = new HashMap<Object, Object>(); 695 make(Object o)696 protected abstract Object make(Object o); 697 made(Object o, Object r)698 protected void made(Object o, Object r) {} 699 keyFor(Object o)700 protected Object keyFor(Object o) { 701 return o; 702 } 703 all()704 Object[] all() { 705 return null; 706 } 707 } 708 709 // annotation values 710 private static HashMap<AnnotationValue, AnnotationValueInfo> mAnnotationValues = 711 new HashMap<AnnotationValue, AnnotationValueInfo>(); 712 private static HashSet<AnnotationValue> mAnnotationValuesNeedingInit = 713 new HashSet<AnnotationValue>(); 714 obtainAnnotationValue(AnnotationValue o, MethodInfo element)715 private static AnnotationValueInfo obtainAnnotationValue(AnnotationValue o, MethodInfo element) { 716 if (o == null) { 717 return null; 718 } 719 AnnotationValueInfo v = mAnnotationValues.get(o); 720 if (v != null) return v; 721 v = new AnnotationValueInfo(element); 722 mAnnotationValues.put(o, v); 723 if (mAnnotationValuesNeedingInit != null) { 724 mAnnotationValuesNeedingInit.add(o); 725 } else { 726 initAnnotationValue(o, v); 727 } 728 return v; 729 } 730 initAnnotationValue(AnnotationValue o, AnnotationValueInfo v)731 private static void initAnnotationValue(AnnotationValue o, AnnotationValueInfo v) { 732 Object orig = o.value(); 733 Object converted; 734 if (orig instanceof Type) { 735 // class literal 736 converted = Converter.obtainType((Type) orig); 737 } else if (orig instanceof FieldDoc) { 738 // enum constant 739 converted = Converter.obtainField((FieldDoc) orig); 740 } else if (orig instanceof AnnotationDesc) { 741 // annotation instance 742 converted = Converter.obtainAnnotationInstance((AnnotationDesc) orig); 743 } else if (orig instanceof AnnotationValue[]) { 744 AnnotationValue[] old = (AnnotationValue[]) orig; 745 ArrayList<AnnotationValueInfo> values = new ArrayList<AnnotationValueInfo>(); 746 for (int i = 0; i < old.length; i++) { 747 values.add(Converter.obtainAnnotationValue(old[i], null)); 748 } 749 converted = values; 750 } else { 751 converted = orig; 752 } 753 v.init(converted); 754 } 755 finishAnnotationValueInit()756 private static void finishAnnotationValueInit() { 757 int depth = 0; 758 while (mAnnotationValuesNeedingInit.size() > 0) { 759 HashSet<AnnotationValue> set = mAnnotationValuesNeedingInit; 760 mAnnotationValuesNeedingInit = new HashSet<AnnotationValue>(); 761 for (AnnotationValue o : set) { 762 AnnotationValueInfo v = mAnnotationValues.get(o); 763 initAnnotationValue(o, v); 764 } 765 depth++; 766 } 767 mAnnotationValuesNeedingInit = null; 768 } 769 } 770