/** * Parses an annotation type definition * * @param docClass * @return */ protected static Annotation ParseAnnotation(ClassDoc docClass) { AnnotationTypeDoc docAnnotation = (AnnotationTypeDoc) docClass; assert (docAnnotation != null); Annotation xmlAnnotation = new Annotation(); xmlAnnotation.name = docClass.name(); xmlAnnotation.qualifiedName = docClass.qualifiedName(); xmlAnnotation.comment = docClass.commentText(); xmlAnnotation.isIncluded = docClass.isIncluded(); xmlAnnotation.scope = DetermineScope(docClass); AnnotationTypeElementDoc[] elements = docAnnotation.elements(); if (elements != null && elements.length > 0) { ArrayList<AnnotationElement> elementList = new ArrayList<AnnotationElement>(); for (AnnotationTypeElementDoc element : elements) { elementList.add(ParseAnnotationElement(element)); } xmlAnnotation.elements = elementList.toArray(new AnnotationElement[] {}); } else { log.debug("No elements in annotation: " + docClass.name()); } xmlAnnotation.annotationInstances = ParseAnnotationInstances(docClass.annotations(), docClass.qualifiedName()); return xmlAnnotation; }
protected void generateDeclsForClass(PrintWriter pw, ClassDoc clazz, String cname) throws ClassNotFoundException { doneHandleTypes = new Hashtable(); /* The following handle types are predefined in "typedefs.h". Suppress inclusion in the output by generating them "into the blue" here. */ genHandleType(null, "java.lang.Class"); genHandleType(null, "java.lang.ClassLoader"); genHandleType(null, "java.lang.Object"); genHandleType(null, "java.lang.String"); genHandleType(null, "java.lang.Thread"); genHandleType(null, "java.lang.ThreadGroup"); genHandleType(null, "java.lang.Throwable"); pw.println("/* LLNI Header for class " + clazz.qualifiedName() + " */" + lineSep); pw.println("#ifndef _Included_" + cname); pw.println("#define _Included_" + cname); pw.println("#include \"typedefs.h\""); pw.println("#include \"llni.h\""); pw.println("#include \"jni.h\"" + lineSep); forwardDecls(pw, clazz); structSectionForClass(pw, clazz, cname); methodSectionForClass(pw, clazz, cname); pw.println("#endif"); }
/** * Constructor. * * @param filename the file to be generated. * @throws IOException * @throws DocletAbortException */ public PackageUseWriter( ConfigurationImpl configuration, ClassUseMapper mapper, DocPath filename, PackageDoc pkgdoc) throws IOException { super(configuration, DocPath.forPackage(pkgdoc).resolve(filename)); this.pkgdoc = pkgdoc; // by examining all classes in this package, find what packages // use these classes - produce a map between using package and // used classes. ClassDoc[] content = pkgdoc.allClasses(); for (int i = 0; i < content.length; ++i) { ClassDoc usedClass = content[i]; Set<ClassDoc> usingClasses = mapper.classToClass.get(usedClass.qualifiedName()); if (usingClasses != null) { for (Iterator<ClassDoc> it = usingClasses.iterator(); it.hasNext(); ) { ClassDoc usingClass = it.next(); PackageDoc usingPackage = usingClass.containingPackage(); Set<ClassDoc> usedClasses = usingPackageToUsedClasses.get(usingPackage.name()); if (usedClasses == null) { usedClasses = new TreeSet<ClassDoc>(); usingPackageToUsedClasses.put(Util.getPackageName(usingPackage), usedClasses); } usedClasses.add(usedClass); } } } }
protected void write(OutputStream o, ClassDoc clazz) throws ClassNotFoundException { String cname = mangleClassName(clazz.qualifiedName()); PrintWriter pw = wrapWriter(o); fields = clazz.fields(); methods = clazz.methods(); generateDeclsForClass(pw, clazz, cname); }
/** Convert the class name into a corresponding URL */ public String classToUrl(ClassDoc cd, boolean rootClass) { // building relative path for context and package diagrams if (contextDoc != null && rootClass) { // determine the context path, relative to the root String packageName = null; if (contextDoc instanceof ClassDoc) { packageName = ((ClassDoc) contextDoc).containingPackage().name(); } else if (contextDoc instanceof PackageDoc) { packageName = ((PackageDoc) contextDoc).name(); } else { return classToUrl(cd.qualifiedName()); } return buildRelativePath(packageName, cd.containingPackage().name()) + cd.name() + ".html"; } else { return classToUrl(cd.qualifiedName()); } }
FieldDefsRes(ClassDoc clazz, FieldDefsRes parent, boolean bottomMost) { this.className = clazz.qualifiedName(); this.parent = parent; this.bottomMost = bottomMost; int byteSize = 0; if (parent == null) this.s = ""; else this.s = parent.s; }
/** * Return the qualified name of the <code>ClassDoc</code> if it's qualifier is not excluded. * Otherwise, return the unqualified <code>ClassDoc</code> name. * * @param cd the <code>ClassDoc</code> to check. */ public String getClassName(ClassDoc cd) { PackageDoc pd = cd.containingPackage(); if (pd != null && shouldExcludeQualifier(cd.containingPackage().name())) { return cd.name(); } else { return cd.qualifiedName(); } }
/** * Parses an interface type definition * * @param docClass * @return */ protected static Interface ParseInterface(ClassDoc docClass) { assert (docClass != null); Interface xmlInterface = new Interface(); xmlInterface.name = docClass.name(); xmlInterface.qualifiedName = docClass.qualifiedName(); xmlInterface.comment = docClass.commentText(); xmlInterface.isIncluded = docClass.isIncluded(); xmlInterface.scope = DetermineScope(docClass); xmlInterface.typeVariables = ParseTypeVariables(docClass.typeParameters(), docClass.typeParamTags()); Type[] interfaces = docClass.interfaceTypes(); ArrayList<String> interfaceTypeNames = new ArrayList<String>(); if (interfaces != null && interfaces.length > 0) { for (Type interfaceType : interfaces) { interfaceTypeNames.add(interfaceType.qualifiedTypeName()); } xmlInterface.interfaces = interfaceTypeNames.toArray(new String[] {}); } MethodDoc[] methods = docClass.methods(); if (methods != null && methods.length > 0) { ArrayList<Method> methodList = new ArrayList<Method>(); for (MethodDoc method : methods) { methodList.add(ParseMethod(method)); } xmlInterface.methods = methodList.toArray(new Method[] {}); } else { log.debug("No methods in interface: " + docClass.name()); } xmlInterface.annotationInstances = ParseAnnotationInstances(docClass.annotations(), docClass.qualifiedName()); return xmlInterface; }
/** * Parses the enum type definition * * @param docClass * @return */ protected static Enum ParseEnum(ClassDoc docClass) { assert (docClass != null); Enum xmlEnum = new Enum(); xmlEnum.name = docClass.name(); xmlEnum.qualifiedName = docClass.qualifiedName(); xmlEnum.comment = docClass.commentText(); xmlEnum.isIncluded = docClass.isIncluded(); xmlEnum.scope = DetermineScope(docClass); Type superClassType = docClass.superclassType(); if (superClassType != null) { xmlEnum.superClass = superClassType.qualifiedTypeName(); } Type[] interfaces = docClass.interfaceTypes(); ArrayList<String> interfaceTypeNames = new ArrayList<String>(); if (interfaces != null && interfaces.length > 0) { for (Type interfaceType : interfaces) { interfaceTypeNames.add(interfaceType.qualifiedTypeName()); } } xmlEnum.extendedFrom = interfaceTypeNames.toArray(new String[] {}); FieldDoc[] fields = docClass.enumConstants(); if (fields != null && fields.length > 0) { ArrayList<EnumField> fieldList = new ArrayList<EnumField>(); for (FieldDoc field : fields) { fieldList.add(ParseEnumField(field)); } xmlEnum.fields = fieldList.toArray(new EnumField[] {}); } xmlEnum.annotationInstances = ParseAnnotationInstances(docClass.annotations(), docClass.qualifiedName()); return xmlEnum; }
@Override protected Map<PLACE_HOLDER, String[]> getDetails(PackageDoc doc) { Map<PLACE_HOLDER, String[]> map = new HashMap<>(); buildDetail(map, PLACE_HOLDER.PACKAGE_NAME, doc.name()); buildDetail(map, PLACE_HOLDER.COMMENT, DocletUtil.renderComment(doc)); StringBuffer sb = new StringBuffer(); ClassDoc[] docs = doc.allClasses(false); if (docs != null) { for (ClassDoc classDoc : docs) { sb.append("<li>"); sb.append("<a href=\"javascript:void(0);\" onclick=\"navigateTo('") .append(classDoc.qualifiedName()) .append("');\">"); sb.append(classDoc.qualifiedName()).append("</a>"); sb.append("</li>"); } } buildDetail(map, PLACE_HOLDER.CHILD_CLASSES, sb.toString()); return map; }
protected void forwardDecls(PrintWriter pw, ClassDoc clazz) throws ClassNotFoundException { ClassDoc clazzfield = null; if (clazz.qualifiedName().equals("java.lang.Object")) return; genHandleType(pw, clazz.qualifiedName()); ClassDoc superClass = clazz.superclass(); if (superClass != null) { String superClassName = superClass.qualifiedName(); forwardDecls(pw, superClass); } for (int i = 0; i < fields.length; i++) { FieldDoc field = (FieldDoc) fields[i]; if (!field.isStatic()) { Type t = field.type(); String tname = t.qualifiedTypeName(); TypeSignature newTypeSig = new TypeSignature(root); String sig = newTypeSig.getTypeSignature(tname); if (sig.charAt(0) != '[') forwardDeclsFromSig(pw, sig); } } for (int i = 0; i < methods.length; i++) { MethodDoc method = (MethodDoc) methods[i]; if (method.isNative()) { Type retType = method.returnType(); String typesig = method.signature(); TypeSignature newTypeSig = new TypeSignature(root); String sig = newTypeSig.getTypeSignature(typesig, retType); if (sig.charAt(0) != '[') forwardDeclsFromSig(pw, sig); } } }
/** Generate the class use list. */ protected void generateClassUseFile() throws IOException { Content body = getClassUseHeader(); HtmlTree div = new HtmlTree(HtmlTag.DIV); div.addStyle(HtmlStyle.classUseContainer); if (pkgSet.size() > 0) { addClassUse(div); } else { div.addContent(getResource("doclet.ClassUse_No.usage.of.0", classdoc.qualifiedName())); } body.addContent(div); addNavLinks(false, body); addBottom(body); printHtmlDocument(null, true, body); }
/** * Build the field information. * * @param node the XML element that specifies which components to document * @param fieldsContentTree content tree to which the documentation will be added */ public void buildFieldInfo(XMLNode node, Content fieldsContentTree) { if (configuration.nocomment) { return; } FieldDoc field = (FieldDoc) currentMember; ClassDoc cd = field.containingClass(); // Process default Serializable field. if ((field.tags("serial").length == 0) && !field.isSynthetic() && configuration.serialwarn) { configuration.message.warning( field.position(), "doclet.MissingSerialTag", cd.qualifiedName(), field.name()); } fieldWriter.addMemberDescription(field, fieldsContentTree); fieldWriter.addMemberTags(field, fieldsContentTree); }
/** * Create a new ClassGraph. * * <p>The packages passed as an argument are the ones specified on the command line. * * <p>Local URLs will be generated for these packages. * * @param root The root of docs as provided by the javadoc API * @param optionProvider The main option provider * @param contextDoc The current context for generating relative links, may be a ClassDoc or a * PackageDoc (used by UMLDoc) */ public ClassGraph(RootDoc root, OptionProvider optionProvider, Doc contextDoc) { this.optionProvider = optionProvider; this.collectionClassDoc = root.classNamed("java.util.Collection"); this.mapClassDoc = root.classNamed("java.util.Map"); this.contextDoc = contextDoc; // to gather the packages containing specified classes, loop thru them and gather // package definitions. User root.specifiedPackages is not safe, since the user // may specify just a list of classes (human users usually don't, but automated tools do) rootClasses = new HashSet<String>(); for (ClassDoc classDoc : root.classes()) { rootClasses.add(classDoc.qualifiedName()); rootClassdocs.put(classDoc.qualifiedName(), classDoc); } Options opt = optionProvider.getGlobalOptions(); if (opt.compact) { linePrefix = ""; linePostfix = ""; } else { linePrefix = "\t"; linePostfix = "\n"; } }
/** * Given an array of <code>Tag</code>s representing this custom tag, return its string * representation. * * @param throwTags the array of <code>ThrowsTag</code>s to convert. * @param writer the TagletWriter that will write this tag. * @param alreadyDocumented the set of exceptions that have already been documented. * @param allowDups True if we allow duplicate throws tags to be documented. * @return the TagletOutput representation of this <code>Tag</code>. */ protected TagletOutput throwsTagsOutput( ThrowsTag[] throwTags, TagletWriter writer, Set<String> alreadyDocumented, boolean allowDups) { TagletOutput result = writer.getOutputInstance(); if (throwTags.length > 0) { for (int i = 0; i < throwTags.length; ++i) { ThrowsTag tt = throwTags[i]; ClassDoc cd = tt.exception(); if ((!allowDups) && (alreadyDocumented.contains(tt.exceptionName()) || (cd != null && alreadyDocumented.contains(cd.qualifiedName())))) { continue; } if (alreadyDocumented.size() == 0) { result.appendOutput(writer.getThrowsHeader()); } result.appendOutput(writer.throwsTagOutput(tt)); alreadyDocumented.add(cd != null ? cd.qualifiedName() : tt.exceptionName()); } } return result; }
/** * Given a class, return the closest visible super class. * * @param classDoc the class we are searching the parent for. * @param configuration the current configuration of the doclet. * @return the closest visible super class. Return null if it cannot be found (i.e. classDoc is * java.lang.Object). */ public static Type getFirstVisibleSuperClass(ClassDoc classDoc, Configuration configuration) { if (classDoc == null) { return null; } Type sup = classDoc.superclassType(); ClassDoc supClassDoc = classDoc.superclass(); while (sup != null && (!(supClassDoc.isPublic() || isLinkable(supClassDoc, configuration)))) { if (supClassDoc.superclass().qualifiedName().equals(supClassDoc.qualifiedName())) break; sup = supClassDoc.superclassType(); supClassDoc = supClassDoc.superclass(); } if (classDoc.equals(supClassDoc)) { return null; } return sup; }
public ThrowsTagImpl(String text, ClassDocImpl contextClass, MemberDocImpl contextMember) { super(text); char[] textarr = text.toCharArray(); int i = 0; for (; i < textarr.length; ++i) { if (!Parser.isWhitespace(textarr[i])) break; } for (; i < textarr.length; ++i) { if (Parser.isWhitespace(textarr[i])) { this.exceptionName = new String(textarr, 0, i).trim(); this.exceptionComment = new String(textarr, i, textarr.length - i).trim(); break; } } if (null != exceptionName) { if (contextClass == null) { this.exception = Main.getRootDoc().classNamed(exceptionName); } else { this.exception = contextClass.findClass(exceptionName); } if (exception != null) this.exceptionName = exception.qualifiedName(); else { if (text.trim().startsWith("<")) { Main.getRootDoc() .printWarning( "Expected exception name but got '" + text + "' in class " + contextClass.getClassName()); } } } else { Main.getRootDoc() .printWarning( "@throws tag in comment for " + contextClass.qualifiedName() + "." + contextMember.name() + " doesn't specify an exception."); } if (this.exceptionComment != null) { setBody(this.exceptionComment, contextClass, contextMember); } }
/** * Get the header for the class use Listing. * * @return a content tree representing the class use header */ protected Content getClassUseHeader() { String cltype = configuration.getText(classdoc.isInterface() ? "doclet.Interface" : "doclet.Class"); String clname = classdoc.qualifiedName(); String title = configuration.getText("doclet.Window_ClassUse_Header", cltype, clname); Content bodyTree = getBody(true, getWindowTitle(title)); addTop(bodyTree); addNavLinks(true, bodyTree); ContentBuilder headContent = new ContentBuilder(); headContent.addContent(getResource("doclet.ClassUse_Title", cltype)); headContent.addContent(new HtmlTree(HtmlTag.BR)); headContent.addContent(clname); Content heading = HtmlTree.HEADING(HtmlConstants.CLASS_PAGE_HEADING, true, HtmlStyle.title, headContent); Content div = HtmlTree.DIV(HtmlStyle.header, heading); bodyTree.addContent(div); return bodyTree; }
private Map<String, List<ProgramElementDoc>> pkgDivide( Map<String, ? extends List<? extends ProgramElementDoc>> classMap) { Map<String, List<ProgramElementDoc>> map = new HashMap<>(); List<? extends ProgramElementDoc> list = classMap.get(classdoc.qualifiedName()); if (list != null) { Collections.sort(list); for (ProgramElementDoc doc : list) { PackageDoc pkg = doc.containingPackage(); pkgSet.add(pkg); List<ProgramElementDoc> inPkg = map.get(pkg.name()); if (inPkg == null) { inPkg = new ArrayList<>(); map.put(pkg.name(), inPkg); } inPkg.add(doc); } } return map; }
protected FieldDefsRes fieldDefs(ClassDoc clazz, String cname, boolean bottomMost) throws ClassNotFoundException { FieldDefsRes res; int offset; boolean didTwoWordFields = false; ClassDoc superclazz = clazz.superclass(); if (superclazz != null) { String supername = superclazz.qualifiedName(); res = new FieldDefsRes(clazz, fieldDefs(superclazz, cname, false), bottomMost); offset = res.parent.byteSize; } else { res = new FieldDefsRes(clazz, null, bottomMost); offset = 0; } FieldDoc[] fields = clazz.fields(); for (int i = 0; i < fields.length; i++) { FieldDoc field = fields[i]; if (doubleAlign && !didTwoWordFields && (offset % 8) == 0) { offset = doTwoWordFields(res, clazz, offset, cname, false); didTwoWordFields = true; } String tc = field.type().typeName(); boolean twoWords = (tc.equals("long") || tc.equals("double")); if (!doubleAlign || !twoWords) { if (doField(res, field, cname, false)) offset += 4; } } if (doubleAlign && !didTwoWordFields) { if ((offset % 8) != 0) offset += 4; offset = doTwoWordFields(res, clazz, offset, cname, true); } res.byteSize = offset; return res; }
/** * Translate from a a controller class to a Controller model. * * @param classDoc * @return */ public static ControllerModel translateToModel(ClassDoc classDoc) { ControllerModel model = new ControllerModel(); // Setup the basic data model.setName(classDoc.name()); model.setClassDescription(classDoc.getRawCommentText()); model.setFullClassName(classDoc.qualifiedName()); // Map the annotations of the class Map<String, Object> annotationMap = mapAnnotation(classDoc.annotations()); // Get the display name and path if they exist model.setDisplayName((String) annotationMap.get(CONTROLLER_INFO_DISPLAY_NAME)); model.setPath((String) annotationMap.get(CONTROLLER_INFO_PATH)); Iterator<MethodDoc> methodIt = FilterUtils.requestMappingIterator(classDoc.methods()); List<MethodModel> methods = new LinkedList<MethodModel>(); model.setMethods(methods); while (methodIt.hasNext()) { MethodDoc methodDoc = methodIt.next(); MethodModel methodModel = translateMethod(methodDoc); methods.add(methodModel); } return model; }
protected void structSectionForClass(PrintWriter pw, ClassDoc jclazz, String cname) throws ClassNotFoundException { String jname = jclazz.qualifiedName(); if (cname.equals("java_lang_Object")) { pw.println("/* struct java_lang_Object is defined in typedefs.h. */"); pw.println(); return; } pw.println("#if !defined(__i386)"); pw.println("#pragma pack(4)"); pw.println("#endif"); pw.println(); pw.println("struct " + cname + " {"); pw.println(" ObjHeader h;"); pw.print(fieldDefs(jclazz, cname)); if (jname.equals("java.lang.Class")) pw.println(" Class *LLNI_mask(cClass);" + " /* Fake field; don't access (see oobj.h) */"); pw.println("};" + lineSep + lineSep + "#pragma pack()"); pw.println(); return; }
/** * Parses the data for a class type definition * * @param docClass * @return */ protected static Class ParseClass(ClassDoc docClass) { assert (docClass != null); Class xmlClass = new Class(); // illegal use of this class. assert (xmlClass != null); xmlClass.name = docClass.name(); xmlClass.qualifiedName = docClass.qualifiedName(); xmlClass.isSerializable = docClass.isSerializable(); xmlClass.isExternalizable = docClass.isExternalizable(); xmlClass.isAbstract = docClass.isAbstract(); xmlClass.isException = docClass.isException(); xmlClass.isError = docClass.isError(); xmlClass.comment = docClass.commentText(); xmlClass.scope = DetermineScope(docClass); xmlClass.isIncluded = docClass.isIncluded(); xmlClass.typeVariables = ParseTypeVariables(docClass.typeParameters(), docClass.typeParamTags()); Type superClassType = docClass.superclassType(); if (superClassType != null) { xmlClass.superClass = ParseType(superClassType); } Type[] interfaces = docClass.interfaceTypes(); ArrayList<TypeInfo> interfaceTypeNames = new ArrayList<TypeInfo>(); if (interfaces != null && interfaces.length > 0) { for (Type interfaceType : interfaces) { interfaceTypeNames.add(ParseType(interfaceType)); } xmlClass.interfaces = interfaceTypeNames.toArray(new TypeInfo[] {}); } ConstructorDoc[] constructors = docClass.constructors(); if (constructors != null && constructors.length > 0) { ArrayList<Constructor> constructorList = new ArrayList<Constructor>(); for (ConstructorDoc constructor : constructors) { constructorList.add(ParseConstructor(constructor)); } xmlClass.constructors = constructorList.toArray(new Constructor[] {}); } else { log.debug("No constructors in class: " + docClass.name()); } MethodDoc[] methods = docClass.methods(); if (methods != null && methods.length > 0) { ArrayList<Method> methodList = new ArrayList<Method>(); for (MethodDoc method : methods) { methodList.add(ParseMethod(method)); } xmlClass.methods = methodList.toArray(new Method[] {}); } else { log.debug("No methods in class: " + docClass.name()); } FieldDoc[] fields = docClass.fields(); if (fields != null && fields.length > 0) { ArrayList<Field> fieldList = new ArrayList<Field>(); for (FieldDoc field : fields) { fieldList.add(ParseField(field)); } xmlClass.fields = fieldList.toArray(new Field[] {}); } xmlClass.annotationInstances = ParseAnnotationInstances(docClass.annotations(), docClass.qualifiedName()); return xmlClass; }
/** * Constructor. * * @param filename the file to be generated. * @throws IOException * @throws DocletAbortException */ public ClassUseWriter( ConfigurationImpl configuration, ClassUseMapper mapper, DocPath filename, ClassDoc classdoc) throws IOException { super(configuration, filename); this.classdoc = classdoc; if (mapper.classToPackageAnnotations.containsKey(classdoc.qualifiedName())) pkgToPackageAnnotations = new TreeSet<>(mapper.classToPackageAnnotations.get(classdoc.qualifiedName())); configuration.currentcd = classdoc; this.pkgSet = new TreeSet<>(); this.pkgToClassTypeParameter = pkgDivide(mapper.classToClassTypeParam); this.pkgToClassAnnotations = pkgDivide(mapper.classToClassAnnotations); this.pkgToMethodTypeParameter = pkgDivide(mapper.classToExecMemberDocTypeParam); this.pkgToMethodArgTypeParameter = pkgDivide(mapper.classToExecMemberDocArgTypeParam); this.pkgToFieldTypeParameter = pkgDivide(mapper.classToFieldDocTypeParam); this.pkgToFieldAnnotations = pkgDivide(mapper.annotationToFieldDoc); this.pkgToMethodReturnTypeParameter = pkgDivide(mapper.classToExecMemberDocReturnTypeParam); this.pkgToMethodAnnotations = pkgDivide(mapper.classToExecMemberDocAnnotations); this.pkgToMethodParameterAnnotations = pkgDivide(mapper.classToExecMemberDocParamAnnotation); this.pkgToSubclass = pkgDivide(mapper.classToSubclass); this.pkgToSubinterface = pkgDivide(mapper.classToSubinterface); this.pkgToImplementingClass = pkgDivide(mapper.classToImplementingClass); this.pkgToField = pkgDivide(mapper.classToField); this.pkgToMethodReturn = pkgDivide(mapper.classToMethodReturn); this.pkgToMethodArgs = pkgDivide(mapper.classToMethodArgs); this.pkgToMethodThrows = pkgDivide(mapper.classToMethodThrows); this.pkgToConstructorAnnotations = pkgDivide(mapper.classToConstructorAnnotations); this.pkgToConstructorParameterAnnotations = pkgDivide(mapper.classToConstructorParamAnnotation); this.pkgToConstructorArgs = pkgDivide(mapper.classToConstructorArgs); this.pkgToConstructorArgTypeParameter = pkgDivide(mapper.classToConstructorDocArgTypeParam); this.pkgToConstructorThrows = pkgDivide(mapper.classToConstructorThrows); // tmp test if (pkgSet.size() > 0 && mapper.classToPackage.containsKey(classdoc.qualifiedName()) && !pkgSet.equals(mapper.classToPackage.get(classdoc.qualifiedName()))) { configuration.root.printWarning( "Internal error: package sets don't match: " + pkgSet + " with: " + mapper.classToPackage.get(classdoc.qualifiedName())); } methodSubWriter = new MethodWriterImpl(this); constrSubWriter = new ConstructorWriterImpl(this); fieldSubWriter = new FieldWriterImpl(this); classSubWriter = new NestedClassWriterImpl(this); classUseTableSummary = configuration.getText("doclet.Use_Table_Summary", configuration.getText("doclet.classes")); subclassUseTableSummary = configuration.getText( "doclet.Use_Table_Summary", configuration.getText("doclet.subclasses")); subinterfaceUseTableSummary = configuration.getText( "doclet.Use_Table_Summary", configuration.getText("doclet.subinterfaces")); fieldUseTableSummary = configuration.getText("doclet.Use_Table_Summary", configuration.getText("doclet.fields")); methodUseTableSummary = configuration.getText("doclet.Use_Table_Summary", configuration.getText("doclet.methods")); constructorUseTableSummary = configuration.getText( "doclet.Use_Table_Summary", configuration.getText("doclet.constructors")); }
public boolean run() { try { // setup additional classes needed for processing, generally these are java ones such as // java.lang.String // adding them here allows them to be used in @outputType Collection<ClassDoc> typeClasses = new ArrayList<ClassDoc>(); addIfNotNull(typeClasses, this.rootDoc.classNamed(java.lang.String.class.getName())); addIfNotNull(typeClasses, this.rootDoc.classNamed(java.lang.Integer.class.getName())); addIfNotNull(typeClasses, this.rootDoc.classNamed(java.lang.Boolean.class.getName())); addIfNotNull(typeClasses, this.rootDoc.classNamed(java.lang.Float.class.getName())); addIfNotNull(typeClasses, this.rootDoc.classNamed(java.lang.Double.class.getName())); addIfNotNull(typeClasses, this.rootDoc.classNamed(java.lang.Character.class.getName())); addIfNotNull(typeClasses, this.rootDoc.classNamed(java.lang.Long.class.getName())); addIfNotNull(typeClasses, this.rootDoc.classNamed(java.lang.Byte.class.getName())); addIfNotNull(typeClasses, this.rootDoc.classNamed(java.util.Date.class.getName())); addIfNotNull(typeClasses, this.rootDoc.classNamed(java.util.Calendar.class.getName())); addIfNotNull(typeClasses, this.rootDoc.classNamed(java.util.Map.class.getName())); addIfNotNull(typeClasses, this.rootDoc.classNamed(java.util.Collection.class.getName())); addIfNotNull(typeClasses, this.rootDoc.classNamed(java.util.Set.class.getName())); addIfNotNull(typeClasses, this.rootDoc.classNamed(java.util.List.class.getName())); addIfNotNull(typeClasses, this.rootDoc.classNamed(java.math.BigInteger.class.getName())); addIfNotNull(typeClasses, this.rootDoc.classNamed(java.math.BigDecimal.class.getName())); addIfNotNull(typeClasses, this.rootDoc.classNamed(java.util.UUID.class.getName())); addIfNotNull(typeClasses, this.rootDoc.classNamed(java.time.DayOfWeek.class.getName())); addIfNotNull(typeClasses, this.rootDoc.classNamed(java.time.Duration.class.getName())); addIfNotNull(typeClasses, this.rootDoc.classNamed(java.time.Instant.class.getName())); addIfNotNull(typeClasses, this.rootDoc.classNamed(java.time.LocalDate.class.getName())); addIfNotNull(typeClasses, this.rootDoc.classNamed(java.time.LocalDateTime.class.getName())); addIfNotNull(typeClasses, this.rootDoc.classNamed(java.time.Month.class.getName())); addIfNotNull(typeClasses, this.rootDoc.classNamed(java.time.MonthDay.class.getName())); addIfNotNull(typeClasses, this.rootDoc.classNamed(java.time.OffsetDateTime.class.getName())); addIfNotNull(typeClasses, this.rootDoc.classNamed(java.time.OffsetTime.class.getName())); addIfNotNull(typeClasses, this.rootDoc.classNamed(java.time.Period.class.getName())); addIfNotNull(typeClasses, this.rootDoc.classNamed(java.time.Year.class.getName())); addIfNotNull(typeClasses, this.rootDoc.classNamed(java.time.YearMonth.class.getName())); addIfNotNull(typeClasses, this.rootDoc.classNamed(java.time.ZoneId.class.getName())); addIfNotNull(typeClasses, this.rootDoc.classNamed(java.time.ZoneOffset.class.getName())); addIfNotNull(typeClasses, this.rootDoc.classNamed(java.time.ZonedDateTime.class.getName())); addIfNotNull(typeClasses, this.rootDoc.classNamed(java.net.URI.class.getName())); addIfNotNull(typeClasses, this.rootDoc.classNamed(java.net.URL.class.getName())); // filter the classes to process Collection<ClassDoc> docletClasses = new ArrayList<ClassDoc>(); for (ClassDoc classDoc : this.rootDoc.classes()) { // see if excluded via its FQN boolean excludeResource = false; if (this.options.getExcludeResourcePrefixes() != null && !this.options.getExcludeResourcePrefixes().isEmpty()) { for (String prefix : this.options.getExcludeResourcePrefixes()) { String className = classDoc.qualifiedName(); if (className.startsWith(prefix)) { excludeResource = true; break; } } } // see if the inclusion filter is set and if so this resource must match this if (!excludeResource && this.options.getIncludeResourcePrefixes() != null && !this.options.getIncludeResourcePrefixes().isEmpty()) { boolean matched = false; for (String prefix : this.options.getIncludeResourcePrefixes()) { String className = classDoc.qualifiedName(); if (className.startsWith(prefix)) { matched = true; break; } } excludeResource = !matched; } if (excludeResource) { continue; } // see if deprecated if (this.options.isExcludeDeprecatedResourceClasses() && ParserHelper.isDeprecated(classDoc, this.options)) { continue; } // see if excluded via a tag if (ParserHelper.hasTag(classDoc, this.options.getExcludeClassTags())) { continue; } docletClasses.add(classDoc); } ClassDocCache classCache = new ClassDocCache(docletClasses); List<ApiDeclaration> declarations = null; // build up set of subresources // do simple parsing to find sub resource classes // these are ones referenced in the return types of methods // which have a path but no http method Map<Type, ClassDoc> subResourceClasses = new HashMap<Type, ClassDoc>(); for (ClassDoc classDoc : docletClasses) { ClassDoc currentClassDoc = classDoc; while (currentClassDoc != null) { for (MethodDoc method : currentClassDoc.methods()) { // if the method has @Path but no Http method then its an entry point to a sub resource if (!ParserHelper.resolveMethodPath(method, this.options).isEmpty() && HttpMethod.fromMethod(method) == null) { ClassDoc subResourceClassDoc = classCache.findByType(method.returnType()); if (subResourceClassDoc != null) { if (this.options.isLogDebug()) { System.out.println( "Adding return type as sub resource class : " + subResourceClassDoc.name() + " for method " + method.name() + " of referencing class " + currentClassDoc.name()); } subResourceClasses.put(method.returnType(), subResourceClassDoc); } } } currentClassDoc = currentClassDoc.superclass(); // ignore parent object class if (!ParserHelper.hasAncestor(currentClassDoc)) { break; } } } // parse with the v2 parser that supports endpoints of the same resource being spread across // resource files Map<String, ApiDeclaration> resourceToDeclaration = new HashMap<String, ApiDeclaration>(); for (ClassDoc classDoc : docletClasses) { CrossClassApiParser classParser = new CrossClassApiParser( this.options, classDoc, docletClasses, subResourceClasses, typeClasses, SWAGGER_VERSION, this.options.getApiVersion(), this.options.getApiBasePath()); classParser.parse(resourceToDeclaration); } Collection<ApiDeclaration> declarationColl = resourceToDeclaration.values(); if (this.options.isLogDebug()) { System.out.println("After parse phase api declarations are: "); for (ApiDeclaration apiDec : declarationColl) { System.out.println( "Api Dec: base path " + apiDec.getBasePath() + ", res path: " + apiDec.getResourcePath()); for (Api api : apiDec.getApis()) { System.out.println("Api path:" + api.getPath()); for (Operation op : api.getOperations()) { System.out.println("Api nick name:" + op.getNickname() + " method " + op.getMethod()); } } } } // add any extra declarations if (this.options.getExtraApiDeclarations() != null && !this.options.getExtraApiDeclarations().isEmpty()) { declarationColl = new ArrayList<ApiDeclaration>(declarationColl); declarationColl.addAll(this.options.getExtraApiDeclarations()); } // set root path on any empty resources for (ApiDeclaration api : declarationColl) { if (api.getResourcePath() == null || api.getResourcePath().isEmpty() || api.getResourcePath().equals("/")) { api.setResourcePath(this.options.getResourceRootPath()); } } // merge the api declarations declarationColl = new ApiDeclarationMerger( SWAGGER_VERSION, this.options.getApiVersion(), this.options.getApiBasePath()) .merge(declarationColl); // clear any empty models for (ApiDeclaration api : declarationColl) { if (api.getModels() != null && api.getModels().isEmpty()) { api.setModels(null); } } declarations = new ArrayList<ApiDeclaration>(declarationColl); // sort the api declarations if needed if (this.options.isSortResourcesByPriority()) { Collections.sort( declarations, new Comparator<ApiDeclaration>() { public int compare(ApiDeclaration dec1, ApiDeclaration dec2) { return Integer.compare(dec1.getPriority(), dec2.getPriority()); } }); } else if (this.options.isSortResourcesByPath()) { Collections.sort( declarations, new Comparator<ApiDeclaration>() { public int compare(ApiDeclaration dec1, ApiDeclaration dec2) { if (dec1 == null || dec1.getResourcePath() == null) { return 1; } if (dec2 == null || dec2.getResourcePath() == null) { return -1; } return dec1.getResourcePath().compareTo(dec2.getResourcePath()); } }); } // sort apis of each declaration if (this.options.isSortApisByPath()) { for (ApiDeclaration dec : declarations) { if (dec.getApis() != null) { Collections.sort( dec.getApis(), new Comparator<Api>() { public int compare(Api o1, Api o2) { if (o1 == null || o1.getPath() == null) { return -1; } return o1.getPath().compareTo(o2.getPath()); } }); } } } writeApis(declarations); // Copy swagger-ui into the output directory. if (this.options.isIncludeSwaggerUi()) { copyUi(); } return true; } catch (IOException e) { System.err.println("Failed to write api docs, err msg: " + e.getMessage()); e.printStackTrace(); return false; } }
@Override public DocReferenceable getClassDocRef(ClassDoc classDoc) { return new UnknownApiRef(classDoc.qualifiedName()); }
/** * Prints the class if needed. * * <p>A class is a rootClass if it's included among the classes returned by RootDoc.classes(), * this information is used to properly compute relative links in diagrams for UMLDoc */ public String printClass(ClassDoc c, boolean rootClass) { ClassInfo ci; boolean toPrint; Options opt = optionProvider.getOptionsFor(c); String className = c.toString(); if ((ci = getClassInfo(className)) != null) toPrint = !ci.nodePrinted; else { toPrint = true; ci = newClassInfo(className, true, hidden(c)); } if (toPrint && !hidden(c) && (!c.isEnum() || opt.showEnumerations)) { // Associate classname's alias String r = className; w.println("\t// " + r); // Create label w.print("\t" + ci.name + " [label="); boolean showMembers = (opt.showAttributes && c.fields().length > 0) || (c.isEnum() && opt.showEnumConstants && c.enumConstants().length > 0) || (opt.showOperations && c.methods().length > 0) || (opt.showConstructors && c.constructors().length > 0); externalTableStart(opt, c.qualifiedName(), classToUrl(c, rootClass)); // Calculate the number of innerTable rows we will emmit int nRows = 1; if (showMembers) { if (opt.showAttributes) nRows++; else if (!c.isEnum() && (opt.showConstructors || opt.showOperations)) nRows++; if (c.isEnum() && opt.showEnumConstants) nRows++; if (!c.isEnum() && (opt.showConstructors || opt.showOperations)) nRows++; } firstInnerTableStart(opt, nRows); if (c.isInterface()) tableLine(Align.CENTER, guilWrap(opt, "interface")); if (c.isEnum()) tableLine(Align.CENTER, guilWrap(opt, "enumeration")); stereotype(opt, c, Align.CENTER); Font font = c.isAbstract() && !c.isInterface() ? Font.CLASS_ABSTRACT : Font.CLASS; String qualifiedName = qualifiedName(opt, r); int startTemplate = qualifiedName.indexOf('<'); int idx = 0; if (startTemplate < 0) idx = qualifiedName.lastIndexOf('.'); else idx = qualifiedName.lastIndexOf('.', startTemplate); if (opt.showComment) tableLine(Align.LEFT, htmlNewline(escape(c.commentText())), opt, Font.CLASS); else if (opt.postfixPackage && idx > 0 && idx < (qualifiedName.length() - 1)) { String packageName = qualifiedName.substring(0, idx); String cn = className.substring(idx + 1); tableLine(Align.CENTER, escape(cn), opt, font); tableLine(Align.CENTER, packageName, opt, Font.PACKAGE); } else { tableLine(Align.CENTER, escape(qualifiedName), opt, font); } tagvalue(opt, c); firstInnerTableEnd(opt, nRows); /* * Warning: The boolean expressions guarding innerTableStart() * in this block, should match those in the code block above * marked: "Calculate the number of innerTable rows we will emmit" */ if (showMembers) { if (opt.showAttributes) { innerTableStart(); FieldDoc[] fields = c.fields(); // if there are no fields, print an empty line to generate proper HTML if (fields.length == 0) tableLine(Align.LEFT, ""); else attributes(opt, c.fields()); innerTableEnd(); } else if (!c.isEnum() && (opt.showConstructors || opt.showOperations)) { // show an emtpy box if we don't show attributes but // we show operations innerTableStart(); tableLine(Align.LEFT, ""); innerTableEnd(); } if (c.isEnum() && opt.showEnumConstants) { innerTableStart(); FieldDoc[] ecs = c.enumConstants(); // if there are no constants, print an empty line to generate proper HTML if (ecs.length == 0) { tableLine(Align.LEFT, ""); } else { for (FieldDoc fd : c.enumConstants()) { tableLine(Align.LEFT, fd.name()); } } innerTableEnd(); } if (!c.isEnum() && (opt.showConstructors || opt.showOperations)) { innerTableStart(); boolean printedLines = false; if (opt.showConstructors) printedLines |= operations(opt, c.constructors()); if (opt.showOperations) printedLines |= operations(opt, c.methods()); if (!printedLines) // if there are no operations nor constructors, // print an empty line to generate proper HTML tableLine(Align.LEFT, ""); innerTableEnd(); } } externalTableEnd(); w.print(", URL=\"" + classToUrl(c, rootClass) + "\""); nodeProperties(opt); // If needed, add a note for this node int ni = 0; for (Tag t : c.tags("note")) { String noteName = "n" + ni + "c" + ci.name; w.print("\t// Note annotation\n"); w.print("\t" + noteName + " [label="); externalTableStart( UmlGraph.getCommentOptions(), c.qualifiedName(), classToUrl(c, rootClass)); innerTableStart(); tableLine( Align.LEFT, htmlNewline(escape(t.text())), UmlGraph.getCommentOptions(), Font.CLASS); innerTableEnd(); externalTableEnd(); nodeProperties(UmlGraph.getCommentOptions()); w.print("\t" + noteName + " -> " + relationNode(c) + "[arrowhead=none];\n"); ni++; } ci.nodePrinted = true; } return ci.name; }
/** * The entry point into the Parser class. * * @param root A RootDoc intstance obtained via the doclet API * @return A XML (XStream) serializable element, containing everything parsed from javadoc doclet */ public static Root ParseRoot(RootDoc root) { processingStorage = new HashMap<PackageDoc, ParserMediary>(); try { md5 = MessageDigest.getInstance("MD5"); } catch (NoSuchAlgorithmException e) { log.error("unable to acquire MD5 algorithm", e); return null; } rootXml = new Root(); ClassDoc[] allClasses = root.classes(); for (ClassDoc classDoc : allClasses) { PackageDoc doc = classDoc.containingPackage(); ParserMediary mediary = null; // the age old 'if I have it pull out existing, if I don't make a new one' if (processingStorage.containsKey(doc)) { mediary = processingStorage.get(doc); } else { mediary = new ParserMediary( doc.name(), doc.commentText(), ParseAnnotationInstances(doc.annotations(), doc.name())); processingStorage.put(doc, mediary); } if (classDoc.isIncluded()) { // dev comment--why do enums show up as ordinary class? if (classDoc.isOrdinaryClass() || classDoc.isException() || classDoc.isError()) { mediary.addClass(ParseClass(classDoc)); } else if (classDoc.isEnum()) { mediary.addEnum(ParseEnum(classDoc)); } else if (isAnnotation(classDoc)) { mediary.addAnnotation(ParseAnnotation(classDoc)); } else if (classDoc.isInterface()) { mediary.addInterface(ParseInterface(classDoc)); } } else { log.debug("Skipping not-included class " + classDoc.qualifiedName()); } } if (processingStorage.size() > 0) { List list = new ArrayList<Package>(); for (ParserMediary mediary : processingStorage.values()) { list.add(mediary.wrapup()); } rootXml.packages = (Package[]) list.toArray(new Package[] {}); } else { log.warn("No packages found!"); } return rootXml; }
/** * For a given elment find the root of the tree, start JavaDoc processing for the whole tree and * cache all results. * * @param element any Java element of an tree */ private void cache(IJavaElement element) throws ConQATException { IResource rootNode = ResourceTraversalUtils.returnRoot(element); Context context = new Context(); PrintWriter errorWriter = new PrintWriter(new Stream2LoggerAdapter(LOGGER, Level.DEBUG, "JavaDoc Error")); PrintWriter warningWriter = new PrintWriter(new Stream2LoggerAdapter(LOGGER, Level.DEBUG, "JavaDoc Warning")); // do not store info messages PrintWriter infoWriter = new PrintWriter(new NullOutputStream()); // This is correct, as the messager attaches itself to the context. new SimpleMessager(context, errorWriter, warningWriter, infoWriter); JavadocTool tool = JavadocTool.make0(context); ModifierFilter showAccess = new ModifierFilter(ModifierFilter.ALL_ACCESS); String encoding = determineEncoding(rootNode); String docLocale = StringUtils.EMPTY_STRING; boolean breakiterator = false; ListBuffer<String[]> options = new ListBuffer<String[]>(); ListBuffer<String> includedElements = addAllChildren(rootNode); boolean docClasses = false; ListBuffer<String> subPackages = new ListBuffer<String>(); ListBuffer<String> excludedPackages = new ListBuffer<String>(); boolean quiet = false; try { RootDocImpl rootDoc = tool.getRootDocImpl( docLocale, encoding, showAccess, includedElements.toList(), options.toList(), breakiterator, subPackages.toList(), excludedPackages.toList(), docClasses, false, quiet); if (rootDoc == null) { throw new ConQATException("Could not analyze JavaDoc for " + rootNode); } Map<String, IJavaResource> classLookup = TraversalUtils.createIdToNodeMap((IJavaResource) rootNode); ClassDoc[] classes = rootDoc.classes(); for (ClassDoc doc : classes) { IJavaResource tmpElement = classLookup.get(doc.qualifiedName()); if (tmpElement instanceof IJavaElement) { cache.put(((IJavaElement) tmpElement).getUniformPath(), doc); } } } catch (Throwable ex) { // The dreaded JavaDoc implementation may throw all kinds of stuff, // including Errors. Hence, we catch throwable here. Additionally, // we minimally support debugging by extracting a somewhat // reasonable message. String message = ex.getMessage(); if (message == null) { message = ex.getClass().getName(); message += StringUtils.obtainStackTrace(ex); } throw new ConQATException(message, ex); } finally { errorWriter.close(); warningWriter.close(); infoWriter.close(); } }