| package jdiff; | |
| import com.sun.javadoc.*; | |
| import com.sun.javadoc.Parameter; | |
| import com.sun.javadoc.ParameterizedType; | |
| import com.sun.javadoc.Type; | |
| import java.util.*; | |
| import java.io.*; | |
| import java.lang.reflect.*; | |
| /** | |
| * Converts a Javadoc RootDoc object into a representation in an | |
| * XML file. | |
| * | |
| * See the file LICENSE.txt for copyright details. | |
| * @author Matthew Doar, mdoar@pobox.com | |
| */ | |
| public class RootDocToXML { | |
| /** Default constructor. */ | |
| public RootDocToXML() { | |
| } | |
| /** | |
| * Write the XML representation of the API to a file. | |
| * | |
| * @param root the RootDoc object passed by Javadoc | |
| * @return true if no problems encountered | |
| */ | |
| public static boolean writeXML(RootDoc root) { | |
| String tempFileName = outputFileName; | |
| if (outputDirectory != null) { | |
| tempFileName = outputDirectory; | |
| if (!tempFileName.endsWith(JDiff.DIR_SEP)) | |
| tempFileName += JDiff.DIR_SEP; | |
| tempFileName += outputFileName; | |
| } | |
| try { | |
| FileOutputStream fos = new FileOutputStream(tempFileName); | |
| outputFile = new PrintWriter(fos); | |
| System.out.println("JDiff: writing the API to file '" + tempFileName + "'..."); | |
| if (root.specifiedPackages().length != 0 || root.specifiedClasses().length != 0) { | |
| RootDocToXML apiWriter = new RootDocToXML(); | |
| apiWriter.emitXMLHeader(); | |
| apiWriter.logOptions(); | |
| apiWriter.processPackages(root); | |
| apiWriter.emitXMLFooter(); | |
| } | |
| outputFile.close(); | |
| } catch(IOException e) { | |
| System.out.println("IO Error while attempting to create " + tempFileName); | |
| System.out.println("Error: " + e.getMessage()); | |
| System.exit(1); | |
| } | |
| // If validation is desired, write out the appropriate api.xsd file | |
| // in the same directory as the XML file. | |
| if (XMLToAPI.validateXML) { | |
| writeXSD(); | |
| } | |
| return true; | |
| } | |
| /** | |
| * Write the XML Schema file used for validation. | |
| */ | |
| public static void writeXSD() { | |
| String xsdFileName = outputFileName; | |
| if (outputDirectory == null) { | |
| int idx = xsdFileName.lastIndexOf('\\'); | |
| int idx2 = xsdFileName.lastIndexOf('/'); | |
| if (idx == -1 && idx2 == -1) { | |
| xsdFileName = ""; | |
| } else if (idx == -1 && idx2 != -1) { | |
| xsdFileName = xsdFileName.substring(0, idx2); | |
| } else if (idx != -1 && idx2 == -1) { | |
| xsdFileName = xsdFileName.substring(0, idx); | |
| } else if (idx != -1 && idx2 != -1) { | |
| int max = idx2 > idx ? idx2 : idx; | |
| xsdFileName = xsdFileName.substring(0, max); | |
| } | |
| } else { | |
| xsdFileName = outputDirectory; | |
| if (!xsdFileName.endsWith(JDiff.DIR_SEP)) | |
| xsdFileName += JDiff.DIR_SEP; | |
| } | |
| xsdFileName += "api.xsd"; | |
| try { | |
| FileOutputStream fos = new FileOutputStream(xsdFileName); | |
| PrintWriter xsdFile = new PrintWriter(fos); | |
| // The contents of the api.xsd file | |
| xsdFile.println("<?xml version=\"1.0\" encoding=\"iso-8859-1\" standalone=\"no\"?>"); | |
| xsdFile.println("<xsd:schema xmlns:xsd=\"https://www.w3.org/2001/XMLSchema\">"); | |
| xsdFile.println(""); | |
| xsdFile.println("<xsd:annotation>"); | |
| xsdFile.println(" <xsd:documentation>"); | |
| xsdFile.println(" Schema for JDiff API representation."); | |
| xsdFile.println(" </xsd:documentation>"); | |
| xsdFile.println("</xsd:annotation>"); | |
| xsdFile.println(); | |
| xsdFile.println("<xsd:element name=\"api\" type=\"apiType\"/>"); | |
| xsdFile.println(""); | |
| xsdFile.println("<xsd:complexType name=\"apiType\">"); | |
| xsdFile.println(" <xsd:sequence>"); | |
| xsdFile.println(" <xsd:element name=\"package\" type=\"packageType\" minOccurs='1' maxOccurs='unbounded'/>"); | |
| xsdFile.println(" </xsd:sequence>"); | |
| xsdFile.println(" <xsd:attribute name=\"name\" type=\"xsd:string\"/>"); | |
| xsdFile.println(" <xsd:attribute name=\"jdversion\" type=\"xsd:string\"/>"); | |
| xsdFile.println("</xsd:complexType>"); | |
| xsdFile.println(); | |
| xsdFile.println("<xsd:complexType name=\"packageType\">"); | |
| xsdFile.println(" <xsd:sequence>"); | |
| xsdFile.println(" <xsd:choice maxOccurs='unbounded'>"); | |
| xsdFile.println(" <xsd:element name=\"class\" type=\"classType\"/>"); | |
| xsdFile.println(" <xsd:element name=\"interface\" type=\"classType\"/>"); | |
| xsdFile.println(" </xsd:choice>"); | |
| xsdFile.println(" <xsd:element name=\"doc\" type=\"xsd:string\" minOccurs='0' maxOccurs='1'/>"); | |
| xsdFile.println(" </xsd:sequence>"); | |
| xsdFile.println(" <xsd:attribute name=\"name\" type=\"xsd:string\"/>"); | |
| xsdFile.println("</xsd:complexType>"); | |
| xsdFile.println(); | |
| xsdFile.println("<xsd:complexType name=\"classType\">"); | |
| xsdFile.println(" <xsd:sequence>"); | |
| xsdFile.println(" <xsd:element name=\"implements\" type=\"interfaceTypeName\" minOccurs='0' maxOccurs='unbounded'/>"); | |
| xsdFile.println(" <xsd:element name=\"constructor\" type=\"constructorType\" minOccurs='0' maxOccurs='unbounded'/>"); | |
| xsdFile.println(" <xsd:element name=\"method\" type=\"methodType\" minOccurs='0' maxOccurs='unbounded'/>"); | |
| xsdFile.println(" <xsd:element name=\"field\" type=\"fieldType\" minOccurs='0' maxOccurs='unbounded'/>"); | |
| xsdFile.println(" <xsd:element name=\"doc\" type=\"xsd:string\" minOccurs='0' maxOccurs='1'/>"); | |
| xsdFile.println(" </xsd:sequence>"); | |
| xsdFile.println(" <xsd:attribute name=\"name\" type=\"xsd:string\"/>"); | |
| xsdFile.println(" <xsd:attribute name=\"extends\" type=\"xsd:string\" use='optional'/>"); | |
| xsdFile.println(" <xsd:attribute name=\"abstract\" type=\"xsd:boolean\"/>"); | |
| xsdFile.println(" <xsd:attribute name=\"src\" type=\"xsd:string\" use='optional'/>"); | |
| xsdFile.println(" <xsd:attribute name=\"static\" type=\"xsd:boolean\"/>"); | |
| xsdFile.println(" <xsd:attribute name=\"final\" type=\"xsd:boolean\"/>"); | |
| xsdFile.println(" <xsd:attribute name=\"deprecated\" type=\"xsd:string\"/>"); | |
| xsdFile.println(" <xsd:attribute name=\"visibility\" type=\"xsd:string\"/>"); | |
| xsdFile.println("</xsd:complexType>"); | |
| xsdFile.println(); | |
| xsdFile.println("<xsd:complexType name=\"interfaceTypeName\">"); | |
| xsdFile.println(" <xsd:attribute name=\"name\" type=\"xsd:string\"/>"); | |
| xsdFile.println("</xsd:complexType>"); | |
| xsdFile.println(); | |
| xsdFile.println("<xsd:complexType name=\"constructorType\">"); | |
| xsdFile.println(" <xsd:sequence>"); | |
| xsdFile.println(" <xsd:element name=\"exception\" type=\"exceptionType\" minOccurs='0' maxOccurs='unbounded'/>"); | |
| xsdFile.println(" <xsd:element name=\"doc\" type=\"xsd:string\" minOccurs='0' maxOccurs='1'/>"); | |
| xsdFile.println(" </xsd:sequence>"); | |
| xsdFile.println(" <xsd:attribute name=\"name\" type=\"xsd:string\"/>"); | |
| xsdFile.println(" <xsd:attribute name=\"type\" type=\"xsd:string\" use='optional'/>"); | |
| xsdFile.println(" <xsd:attribute name=\"src\" type=\"xsd:string\" use='optional'/>"); | |
| xsdFile.println(" <xsd:attribute name=\"static\" type=\"xsd:boolean\"/>"); | |
| xsdFile.println(" <xsd:attribute name=\"final\" type=\"xsd:boolean\"/>"); | |
| xsdFile.println(" <xsd:attribute name=\"deprecated\" type=\"xsd:string\"/>"); | |
| xsdFile.println(" <xsd:attribute name=\"visibility\" type=\"xsd:string\"/>"); | |
| xsdFile.println("</xsd:complexType>"); | |
| xsdFile.println(); | |
| xsdFile.println("<xsd:complexType name=\"paramsType\">"); | |
| xsdFile.println(" <xsd:attribute name=\"name\" type=\"xsd:string\"/>"); | |
| xsdFile.println(" <xsd:attribute name=\"type\" type=\"xsd:string\"/>"); | |
| xsdFile.println("</xsd:complexType>"); | |
| xsdFile.println(); | |
| xsdFile.println("<xsd:complexType name=\"exceptionType\">"); | |
| xsdFile.println(" <xsd:attribute name=\"name\" type=\"xsd:string\"/>"); | |
| xsdFile.println(" <xsd:attribute name=\"type\" type=\"xsd:string\"/>"); | |
| xsdFile.println("</xsd:complexType>"); | |
| xsdFile.println(); | |
| xsdFile.println("<xsd:complexType name=\"methodType\">"); | |
| xsdFile.println(" <xsd:sequence>"); | |
| xsdFile.println(" <xsd:element name=\"param\" type=\"paramsType\" minOccurs='0' maxOccurs='unbounded'/>"); | |
| xsdFile.println(" <xsd:element name=\"exception\" type=\"exceptionType\" minOccurs='0' maxOccurs='unbounded'/>"); | |
| xsdFile.println(" <xsd:element name=\"doc\" type=\"xsd:string\" minOccurs='0' maxOccurs='1'/>"); | |
| xsdFile.println(" </xsd:sequence>"); | |
| xsdFile.println(" <xsd:attribute name=\"name\" type=\"xsd:string\"/>"); | |
| xsdFile.println(" <xsd:attribute name=\"return\" type=\"xsd:string\" use='optional'/>"); | |
| xsdFile.println(" <xsd:attribute name=\"abstract\" type=\"xsd:boolean\"/>"); | |
| xsdFile.println(" <xsd:attribute name=\"native\" type=\"xsd:boolean\"/>"); | |
| xsdFile.println(" <xsd:attribute name=\"synchronized\" type=\"xsd:boolean\"/>"); | |
| xsdFile.println(" <xsd:attribute name=\"src\" type=\"xsd:string\" use='optional'/>"); | |
| xsdFile.println(" <xsd:attribute name=\"static\" type=\"xsd:boolean\"/>"); | |
| xsdFile.println(" <xsd:attribute name=\"final\" type=\"xsd:boolean\"/>"); | |
| xsdFile.println(" <xsd:attribute name=\"deprecated\" type=\"xsd:string\"/>"); | |
| xsdFile.println(" <xsd:attribute name=\"visibility\" type=\"xsd:string\"/>"); | |
| xsdFile.println("</xsd:complexType>"); | |
| xsdFile.println(); | |
| xsdFile.println("<xsd:complexType name=\"fieldType\">"); | |
| xsdFile.println(" <xsd:sequence>"); | |
| xsdFile.println(" <xsd:element name=\"doc\" type=\"xsd:string\" minOccurs='0' maxOccurs='1'/>"); | |
| xsdFile.println(" </xsd:sequence>"); | |
| xsdFile.println(" <xsd:attribute name=\"name\" type=\"xsd:string\"/>"); | |
| xsdFile.println(" <xsd:attribute name=\"type\" type=\"xsd:string\"/>"); | |
| xsdFile.println(" <xsd:attribute name=\"transient\" type=\"xsd:boolean\"/>"); | |
| xsdFile.println(" <xsd:attribute name=\"volatile\" type=\"xsd:boolean\"/>"); | |
| xsdFile.println(" <xsd:attribute name=\"value\" type=\"xsd:string\" use='optional'/>"); | |
| xsdFile.println(" <xsd:attribute name=\"src\" type=\"xsd:string\" use='optional'/>"); | |
| xsdFile.println(" <xsd:attribute name=\"static\" type=\"xsd:boolean\"/>"); | |
| xsdFile.println(" <xsd:attribute name=\"final\" type=\"xsd:boolean\"/>"); | |
| xsdFile.println(" <xsd:attribute name=\"deprecated\" type=\"xsd:string\"/>"); | |
| xsdFile.println(" <xsd:attribute name=\"visibility\" type=\"xsd:string\"/>"); | |
| xsdFile.println("</xsd:complexType>"); | |
| xsdFile.println(); | |
| xsdFile.println("</xsd:schema>"); | |
| xsdFile.close(); | |
| } catch(IOException e) { | |
| System.out.println("IO Error while attempting to create " + xsdFileName); | |
| System.out.println("Error: " + e.getMessage()); | |
| System.exit(1); | |
| } | |
| } | |
| /** | |
| * Write the options which were used to generate this XML file | |
| * out as XML comments. | |
| */ | |
| public void logOptions() { | |
| outputFile.print("<!-- "); | |
| outputFile.print(" Command line arguments = " + Options.cmdOptions); | |
| outputFile.println(" -->"); | |
| } | |
| /** | |
| * Process each package and the classes/interfaces within it. | |
| * | |
| * @param pd an array of PackageDoc objects | |
| */ | |
| public void processPackages(RootDoc root) { | |
| PackageDoc[] specified_pd = root.specifiedPackages(); | |
| Map pdl = new TreeMap(); | |
| for (int i = 0; specified_pd != null && i < specified_pd.length; i++) { | |
| pdl.put(specified_pd[i].name(), specified_pd[i]); | |
| } | |
| // Classes may be specified separately, so merge their packages into the | |
| // list of specified packages. | |
| ClassDoc[] cd = root.specifiedClasses(); | |
| // This is lists of the specific classes to document | |
| Map classesToUse = new HashMap(); | |
| for (int i = 0; cd != null && i < cd.length; i++) { | |
| PackageDoc cpd = cd[i].containingPackage(); | |
| if (cpd == null && !packagesOnly) { | |
| // If the RootDoc object has been created from a jar file | |
| // this duplicates classes, so we have to be able to disable it. | |
| // TODO this is still null? | |
| cpd = root.packageNamed("anonymous"); | |
| } | |
| String pkgName = cpd.name(); | |
| String className = cd[i].name(); | |
| if (trace) System.out.println("Found package " + pkgName + " for class " + className); | |
| if (!pdl.containsKey(pkgName)) { | |
| if (trace) System.out.println("Adding new package " + pkgName); | |
| pdl.put(pkgName, cpd); | |
| } | |
| // Keep track of the specific classes to be used for this package | |
| List classes; | |
| if (classesToUse.containsKey(pkgName)) { | |
| classes = (ArrayList) classesToUse.get(pkgName); | |
| } else { | |
| classes = new ArrayList(); | |
| } | |
| classes.add(cd[i]); | |
| classesToUse.put(pkgName, classes); | |
| } | |
| PackageDoc[] pd = (PackageDoc[]) pdl.values().toArray(new PackageDoc[0]); | |
| for (int i = 0; pd != null && i < pd.length; i++) { | |
| String pkgName = pd[i].name(); | |
| // Check for an exclude tag in the package doc block, but not | |
| // in the package.htm[l] file. | |
| if (!shownElement(pd[i], null)) | |
| continue; | |
| if (trace) System.out.println("PROCESSING PACKAGE: " + pkgName); | |
| outputFile.println("<package name=\"" + pkgName + "\">"); | |
| int tagCount = pd[i].tags().length; | |
| if (trace) System.out.println("#tags: " + tagCount); | |
| List classList; | |
| if (classesToUse.containsKey(pkgName)) { | |
| // Use only the specified classes in the package | |
| System.out.println("Using the specified classes"); | |
| classList = (ArrayList) classesToUse.get(pkgName); | |
| } else { | |
| // Use all classes in the package | |
| classList = new LinkedList(Arrays.asList(pd[i].allClasses())); | |
| } | |
| Collections.sort(classList); | |
| ClassDoc[] classes = new ClassDoc[classList.size()]; | |
| classes = (ClassDoc[])classList.toArray(classes); | |
| processClasses(classes, pkgName); | |
| addPkgDocumentation(root, pd[i], 2); | |
| outputFile.println("</package>"); | |
| } | |
| } // processPackages | |
| /** | |
| * Process classes and interfaces. | |
| * | |
| * @param cd An array of ClassDoc objects. | |
| */ | |
| public void processClasses(ClassDoc[] cd, String pkgName) { | |
| if (cd.length == 0) | |
| return; | |
| if (trace) System.out.println("PROCESSING CLASSES, number=" + cd.length); | |
| for (int i = 0; i < cd.length; i++) { | |
| String className = cd[i].name(); | |
| if (trace) System.out.println("PROCESSING CLASS/IFC: " + className); | |
| // Only save the shown elements | |
| if (!shownElement(cd[i], classVisibilityLevel)) | |
| continue; | |
| boolean isInterface = false; | |
| if (cd[i].isInterface()) | |
| isInterface = true; | |
| if (isInterface) { | |
| outputFile.println(" <!-- start interface " + pkgName + "." + className + " -->"); | |
| outputFile.print(" <interface name=\"" + className + "\""); | |
| } else { | |
| outputFile.println(" <!-- start class " + pkgName + "." + className + " -->"); | |
| outputFile.print(" <class name=\"" + className + "\""); | |
| } | |
| // Add attributes to the class element | |
| Type parent = cd[i].superclassType(); | |
| if (parent != null) | |
| outputFile.println(" extends=\"" + buildEmittableTypeString(parent) + "\""); | |
| outputFile.println(" abstract=\"" + cd[i].isAbstract() + "\""); | |
| addCommonModifiers(cd[i], 4); | |
| outputFile.println(">"); | |
| // Process class members. (Treat inner classes as members.) | |
| processInterfaces(cd[i].interfaceTypes()); | |
| processConstructors(cd[i].constructors()); | |
| processMethods(cd[i], cd[i].methods()); | |
| processFields(cd[i].fields()); | |
| addDocumentation(cd[i], 4); | |
| if (isInterface) { | |
| outputFile.println(" </interface>"); | |
| outputFile.println(" <!-- end interface " + pkgName + "." + className + " -->"); | |
| } else { | |
| outputFile.println(" </class>"); | |
| outputFile.println(" <!-- end class " + pkgName + "." + className + " -->"); | |
| } | |
| // Inner classes have already been added. | |
| /* | |
| ClassDoc[] ic = cd[i].innerClasses(); | |
| for (int k = 0; k < ic.length; k++) { | |
| System.out.println("Inner class " + k + ", name = " + ic[k].name()); | |
| } | |
| */ | |
| }//for | |
| }//processClasses() | |
| /** | |
| * Add qualifiers for the program element as attributes. | |
| * | |
| * @param ped The given program element. | |
| */ | |
| public void addCommonModifiers(ProgramElementDoc ped, int indent) { | |
| addSourcePosition(ped, indent); | |
| // Static and final and visibility on one line | |
| for (int i = 0; i < indent; i++) outputFile.print(" "); | |
| outputFile.print("static=\"" + ped.isStatic() + "\""); | |
| outputFile.print(" final=\"" + ped.isFinal() + "\""); | |
| // Visibility | |
| String visibility = null; | |
| if (ped.isPublic()) | |
| visibility = "public"; | |
| else if (ped.isProtected()) | |
| visibility = "protected"; | |
| else if (ped.isPackagePrivate()) | |
| visibility = "package"; | |
| else if (ped.isPrivate()) | |
| visibility = "private"; | |
| outputFile.println(" visibility=\"" + visibility + "\""); | |
| // Deprecation on its own line | |
| for (int i = 0; i < indent; i++) outputFile.print(" "); | |
| boolean isDeprecated = false; | |
| Tag[] ta = ((Doc)ped).tags("deprecated"); | |
| if (ta.length != 0) { | |
| isDeprecated = true; | |
| } | |
| if (ta.length > 1) { | |
| System.out.println("JDiff: warning: multiple @deprecated tags found in comments for " + ped.name() + ". Using the first one only."); | |
| System.out.println("Text is: " + ((Doc)ped).getRawCommentText()); | |
| } | |
| if (isDeprecated) { | |
| String text = ta[0].text(); // Use only one @deprecated tag | |
| if (text != null && text.compareTo("") != 0) { | |
| int idx = endOfFirstSentence(text); | |
| if (idx == 0) { | |
| // No useful comment | |
| outputFile.print("deprecated=\"deprecated, no comment\""); | |
| } else { | |
| String fs = null; | |
| if (idx == -1) | |
| fs = text; | |
| else | |
| fs = text.substring(0, idx+1); | |
| String st = API.hideHTMLTags(fs); | |
| outputFile.print("deprecated=\"" + st + "\""); | |
| } | |
| } else { | |
| outputFile.print("deprecated=\"deprecated, no comment\""); | |
| } | |
| } else { | |
| outputFile.print("deprecated=\"not deprecated\""); | |
| } | |
| } //addQualifiers() | |
| /** | |
| * Insert the source code details, if available. | |
| * | |
| * @param ped The given program element. | |
| */ | |
| public void addSourcePosition(ProgramElementDoc ped, int indent) { | |
| if (!addSrcInfo) | |
| return; | |
| if (JDiff.javaVersion.startsWith("1.1") || | |
| JDiff.javaVersion.startsWith("1.2") || | |
| JDiff.javaVersion.startsWith("1.3")) { | |
| return; // position() only appeared in J2SE1.4 | |
| } | |
| try { | |
| // Could cache the method for improved performance | |
| Class c = ProgramElementDoc.class; | |
| Method m = c.getMethod("position", (Class[]) null); | |
| Object sp = m.invoke(ped, (Object[]) null); | |
| if (sp != null) { | |
| for (int i = 0; i < indent; i++) outputFile.print(" "); | |
| outputFile.println("src=\"" + sp + "\""); | |
| } | |
| } catch (NoSuchMethodException e2) { | |
| System.err.println("Error: method \"position\" not found"); | |
| e2.printStackTrace(); | |
| } catch (IllegalAccessException e4) { | |
| System.err.println("Error: class not permitted to be instantiated"); | |
| e4.printStackTrace(); | |
| } catch (InvocationTargetException e5) { | |
| System.err.println("Error: method \"position\" could not be invoked"); | |
| e5.printStackTrace(); | |
| } catch (Exception e6) { | |
| System.err.println("Error: "); | |
| e6.printStackTrace(); | |
| } | |
| } | |
| /** | |
| * Process the interfaces implemented by the class. | |
| * | |
| * @param ifaces An array of ClassDoc objects | |
| */ | |
| public void processInterfaces(Type[] ifaces) { | |
| if (trace) System.out.println("PROCESSING INTERFACES, number=" + ifaces.length); | |
| for (int i = 0; i < ifaces.length; i++) { | |
| String ifaceName = buildEmittableTypeString(ifaces[i]); | |
| if (trace) System.out.println("PROCESSING INTERFACE: " + ifaceName); | |
| outputFile.println(" <implements name=\"" + ifaceName + "\"/>"); | |
| }//for | |
| }//processInterfaces() | |
| /** | |
| * Process the constructors in the class. | |
| * | |
| * @param ct An array of ConstructorDoc objects | |
| */ | |
| public void processConstructors(ConstructorDoc[] ct) { | |
| if (trace) System.out.println("PROCESSING CONSTRUCTORS, number=" + ct.length); | |
| for (int i = 0; i < ct.length; i++) { | |
| String ctorName = ct[i].name(); | |
| if (trace) System.out.println("PROCESSING CONSTRUCTOR: " + ctorName); | |
| // Only save the shown elements | |
| if (!shownElement(ct[i], memberVisibilityLevel)) | |
| continue; | |
| outputFile.print(" <constructor name=\"" + ctorName + "\""); | |
| Parameter[] params = ct[i].parameters(); | |
| boolean first = true; | |
| if (params.length != 0) { | |
| outputFile.print(" type=\""); | |
| for (int j = 0; j < params.length; j++) { | |
| if (!first) | |
| outputFile.print(", "); | |
| emitType(params[j].type()); | |
| first = false; | |
| } | |
| outputFile.println("\""); | |
| } else | |
| outputFile.println(); | |
| addCommonModifiers(ct[i], 6); | |
| outputFile.println(">"); | |
| // Generate the exception elements if any exceptions are thrown | |
| processExceptions(ct[i].thrownExceptions()); | |
| addDocumentation(ct[i], 6); | |
| outputFile.println(" </constructor>"); | |
| }//for | |
| }//processConstructors() | |
| /** | |
| * Process all exceptions thrown by a constructor or method. | |
| * | |
| * @param cd An array of ClassDoc objects | |
| */ | |
| public void processExceptions(ClassDoc[] cd) { | |
| if (trace) System.out.println("PROCESSING EXCEPTIONS, number=" + cd.length); | |
| for (int i = 0; i < cd.length; i++) { | |
| String exceptionName = cd[i].name(); | |
| if (trace) System.out.println("PROCESSING EXCEPTION: " + exceptionName); | |
| outputFile.print(" <exception name=\"" + exceptionName + "\" type=\""); | |
| emitType(cd[i]); | |
| outputFile.println("\"/>"); | |
| }//for | |
| }//processExceptions() | |
| /** | |
| * Process the methods in the class. | |
| * | |
| * @param md An array of MethodDoc objects | |
| */ | |
| public void processMethods(ClassDoc cd, MethodDoc[] md) { | |
| if (trace) System.out.println("PROCESSING " +cd.name()+" METHODS, number = " + md.length); | |
| for (int i = 0; i < md.length; i++) { | |
| String methodName = md[i].name(); | |
| if (trace) System.out.println("PROCESSING METHOD: " + methodName); | |
| // Skip <init> and <clinit> | |
| if (methodName.startsWith("<")) | |
| continue; | |
| // Only save the shown elements | |
| if (!shownElement(md[i], memberVisibilityLevel)) | |
| continue; | |
| outputFile.print(" <method name=\"" + methodName + "\""); | |
| com.sun.javadoc.Type retType = md[i].returnType(); | |
| if (retType.qualifiedTypeName().compareTo("void") == 0) { | |
| // Don't add a return attribute if the return type is void | |
| outputFile.println(); | |
| } else { | |
| outputFile.print(" return=\""); | |
| emitType(retType); | |
| outputFile.println("\""); | |
| } | |
| outputFile.print(" abstract=\"" + md[i].isAbstract() + "\""); | |
| outputFile.print(" native=\"" + md[i].isNative() + "\""); | |
| outputFile.println(" synchronized=\"" + md[i].isSynchronized() + "\""); | |
| addCommonModifiers(md[i], 6); | |
| outputFile.println(">"); | |
| // Generate the parameter elements, if any | |
| Parameter[] params = md[i].parameters(); | |
| for (int j = 0; j < params.length; j++) { | |
| outputFile.print(" <param name=\"" + params[j].name() + "\""); | |
| outputFile.print(" type=\""); | |
| emitType(params[j].type()); | |
| outputFile.println("\"/>"); | |
| } | |
| // Generate the exception elements if any exceptions are thrown | |
| processExceptions(md[i].thrownExceptions()); | |
| addDocumentation(md[i], 6); | |
| outputFile.println(" </method>"); | |
| }//for | |
| }//processMethods() | |
| /** | |
| * Process the fields in the class. | |
| * | |
| * @param fd An array of FieldDoc objects | |
| */ | |
| public void processFields(FieldDoc[] fd) { | |
| if (trace) System.out.println("PROCESSING FIELDS, number=" + fd.length); | |
| for (int i = 0; i < fd.length; i++) { | |
| String fieldName = fd[i].name(); | |
| if (trace) System.out.println("PROCESSING FIELD: " + fieldName); | |
| // Only save the shown elements | |
| if (!shownElement(fd[i], memberVisibilityLevel)) | |
| continue; | |
| outputFile.print(" <field name=\"" + fieldName + "\""); | |
| outputFile.print(" type=\""); | |
| emitType(fd[i].type()); | |
| outputFile.println("\""); | |
| outputFile.print(" transient=\"" + fd[i].isTransient() + "\""); | |
| outputFile.println(" volatile=\"" + fd[i].isVolatile() + "\""); | |
| /* JDK 1.4 and later */ | |
| /* | |
| String value = fd[i].constantValueExpression(); | |
| if (value != null) | |
| outputFile.println(" value=\"" + value + "\""); | |
| */ | |
| addCommonModifiers(fd[i], 6); | |
| outputFile.println(">"); | |
| addDocumentation(fd[i], 6); | |
| outputFile.println(" </field>"); | |
| }//for | |
| }//processFields() | |
| /** | |
| * Emit the type name. Removed any prefixed warnings about ambiguity. | |
| * The type maybe an array. | |
| * | |
| * @param type A Type object. | |
| */ | |
| public void emitType(com.sun.javadoc.Type type) { | |
| String name = buildEmittableTypeString(type); | |
| if (name == null) | |
| return; | |
| outputFile.print(name); | |
| } | |
| /** | |
| * Build the emittable type name. The type may be an array and/or | |
| * a generic type. | |
| * | |
| * @param type A Type object | |
| * @return The emittable type name | |
| */ | |
| private String buildEmittableTypeString(com.sun.javadoc.Type type) { | |
| if (type == null) { | |
| return null; | |
| } | |
| // type.toString() returns the fully qualified name of the type | |
| // including the dimension and the parameters we just need to | |
| // escape the generic parameters brackets so that the XML | |
| // generated is correct | |
| String name = type.toString().replaceAll("<", "<").replaceAll(">", ">"); | |
| if (name.startsWith("<<ambiguous>>")) { | |
| name = name.substring(13); | |
| } | |
| return name; | |
| } | |
| /** | |
| * Emit the XML header. | |
| */ | |
| public void emitXMLHeader() { | |
| outputFile.println("<?xml version=\"1.0\" encoding=\"iso-8859-1\" standalone=\"no\"?>"); | |
| outputFile.println("<!-- Generated by the JDiff Javadoc doclet -->"); | |
| outputFile.println("<!-- (" + JDiff.jDiffLocation + ") -->"); | |
| outputFile.println("<!-- on " + new Date() + " -->"); | |
| outputFile.println(); | |
| /* No need for this any longer, since doc block text is in an CDATA element | |
| outputFile.println("<!-- XML Schema is used, but XHTML transitional DTD is needed for nbsp -->"); | |
| outputFile.println("<!-- entity definitions etc.-->"); | |
| outputFile.println("<!DOCTYPE api"); | |
| outputFile.println(" PUBLIC \"-//W3C//DTD XHTML 1.0 Transitional//EN\""); | |
| outputFile.println(" \"" + baseURI + "/TR/xhtml1/DTD/xhtml1-transitional.dtd\">"); | |
| */ | |
| outputFile.println("<api"); | |
| outputFile.println(" xmlns:xsi='" + baseURI + "/2001/XMLSchema-instance'"); | |
| outputFile.println(" xsi:noNamespaceSchemaLocation='api.xsd'"); | |
| outputFile.println(" name=\"" + apiIdentifier + "\""); | |
| outputFile.println(" jdversion=\"" + JDiff.version + "\">"); | |
| outputFile.println(); | |
| } | |
| /** | |
| * Emit the XML footer. | |
| */ | |
| public void emitXMLFooter() { | |
| outputFile.println(); | |
| outputFile.println("</api>"); | |
| } | |
| /** | |
| * Determine if the program element is shown, according to the given | |
| * level of visibility. | |
| * | |
| * @param ped The given program element. | |
| * @param visLevel The desired visibility level; "public", "protected", | |
| * "package" or "private". If null, only check for an exclude tag. | |
| * @return boolean Set if this element is shown. | |
| */ | |
| public boolean shownElement(Doc doc, String visLevel) { | |
| // If a doc block contains @exclude or a similar such tag, | |
| // then don't display it. | |
| if (doExclude && excludeTag != null && doc != null) { | |
| String rct = doc.getRawCommentText(); | |
| if (rct != null && rct.indexOf(excludeTag) != -1) { | |
| return false; | |
| } | |
| } | |
| if (visLevel == null) { | |
| return true; | |
| } | |
| ProgramElementDoc ped = null; | |
| if (doc instanceof ProgramElementDoc) { | |
| ped = (ProgramElementDoc)doc; | |
| } | |
| if (visLevel.compareTo("private") == 0) | |
| return true; | |
| // Show all that is not private | |
| if (visLevel.compareTo("package") == 0) | |
| return !ped.isPrivate(); | |
| // Show all that is not private or package | |
| if (visLevel.compareTo("protected") == 0) | |
| return !(ped.isPrivate() || ped.isPackagePrivate()); | |
| // Show all that is not private or package or protected, | |
| // i.e. all that is public | |
| if (visLevel.compareTo("public") == 0) | |
| return ped.isPublic(); | |
| return false; | |
| } //shownElement() | |
| /** | |
| * Strip out non-printing characters, replacing them with a character | |
| * which will not change where the end of the first sentence is found. | |
| * This character is the hash mark, '#'. | |
| */ | |
| public String stripNonPrintingChars(String s, Doc doc) { | |
| if (!stripNonPrintables) | |
| return s; | |
| char[] sa = s.toCharArray(); | |
| for (int i = 0; i < sa.length; i++) { | |
| char c = sa[i]; | |
| // TODO still have an issue with Unicode: 0xfc in java.lang.String.toUpperCase comments | |
| // if (Character.isDefined(c)) | |
| if (Character.isLetterOrDigit(c)) | |
| continue; | |
| // There must be a better way that is still platform independent! | |
| if (c == ' ' || | |
| c == '.' || | |
| c == ',' || | |
| c == '\r' || | |
| c == '\t' || | |
| c == '\n' || | |
| c == '!' || | |
| c == '?' || | |
| c == ';' || | |
| c == ':' || | |
| c == '[' || | |
| c == ']' || | |
| c == '(' || | |
| c == ')' || | |
| c == '~' || | |
| c == '@' || | |
| c == '#' || | |
| c == '$' || | |
| c == '%' || | |
| c == '^' || | |
| c == '&' || | |
| c == '*' || | |
| c == '-' || | |
| c == '=' || | |
| c == '+' || | |
| c == '_' || | |
| c == '|' || | |
| c == '\\' || | |
| c == '/' || | |
| c == '\'' || | |
| c == '}' || | |
| c == '{' || | |
| c == '"' || | |
| c == '<' || | |
| c == '>' || | |
| c == '`' | |
| ) | |
| continue; | |
| /* Doesn't seem to return the expected values? | |
| int val = Character.getNumericValue(c); | |
| // if (s.indexOf("which is also a test for non-printable") != -1) | |
| // System.out.println("** Char " + i + "[" + c + "], val =" + val); //DEBUG | |
| // Ranges from https://www.unicode.org/unicode/reports/tr20/ | |
| // Should really replace 0x2028 and 0x2029 with <br/> | |
| if (val == 0x0 || | |
| inRange(val, 0x2028, 0x2029) || | |
| inRange(val, 0x202A, 0x202E) || | |
| inRange(val, 0x206A, 0x206F) || | |
| inRange(val, 0xFFF9, 0xFFFC) || | |
| inRange(val, 0xE0000, 0xE007F)) { | |
| if (trace) { | |
| System.out.println("Warning: changed non-printing character " + sa[i] + " in " + doc.name()); | |
| } | |
| sa[i] = '#'; | |
| } | |
| */ | |
| // Replace the non-printable character with a printable character | |
| // which does not change the end of the first sentence | |
| sa[i] = '#'; | |
| } | |
| return new String(sa); | |
| } | |
| /** Return true if val is in the range [min|max], inclusive. */ | |
| public boolean inRange(int val, int min, int max) { | |
| if (val < min) | |
| return false; | |
| if (val > max) | |
| return false; | |
| return true; | |
| } | |
| /** | |
| * Add at least the first sentence from a doc block to the API. This is | |
| * used by the report generator if no comment is provided. | |
| * Need to make sure that HTML tags are not confused with XML tags. | |
| * This could be done by stuffing the < character to another string | |
| * or by handling HTML in the parser. This second option seems neater. Note that | |
| * XML expects all element tags to have either a closing "/>" or a matching | |
| * end element tag. Due to the difficulties of converting incorrect HTML | |
| * to XHTML, the first option is used. | |
| */ | |
| public void addDocumentation(ProgramElementDoc ped, int indent) { | |
| String rct = ((Doc)ped).getRawCommentText(); | |
| if (rct != null) { | |
| rct = stripNonPrintingChars(rct, (Doc)ped); | |
| rct = rct.trim(); | |
| if (rct.compareTo("") != 0 && | |
| rct.indexOf(Comments.placeHolderText) == -1 && | |
| rct.indexOf("InsertOtherCommentsHere") == -1) { | |
| int idx = endOfFirstSentence(rct); | |
| if (idx == 0) | |
| return; | |
| for (int i = 0; i < indent; i++) outputFile.print(" "); | |
| outputFile.println("<doc>"); | |
| for (int i = 0; i < indent; i++) outputFile.print(" "); | |
| String firstSentence = null; | |
| if (idx == -1) | |
| firstSentence = rct; | |
| else | |
| firstSentence = rct.substring(0, idx+1); | |
| boolean checkForAts = false; | |
| if (checkForAts && firstSentence.indexOf("@") != -1 && | |
| firstSentence.indexOf("@link") == -1) { | |
| System.out.println("Warning: @ tag seen in comment: " + | |
| firstSentence); | |
| } | |
| String firstSentenceNoTags = API.stuffHTMLTags(firstSentence); | |
| outputFile.println(firstSentenceNoTags); | |
| for (int i = 0; i < indent; i++) outputFile.print(" "); | |
| outputFile.println("</doc>"); | |
| } | |
| } | |
| } | |
| /** | |
| * Add at least the first sentence from a doc block for a package to the API. This is | |
| * used by the report generator if no comment is provided. | |
| * The default source tree may not include the package.html files, so | |
| * this may be unavailable in many cases. | |
| * Need to make sure that HTML tags are not confused with XML tags. | |
| * This could be done by stuffing the < character to another string | |
| * or by handling HTML in the parser. This second option is neater. Note that | |
| * XML expects all element tags to have either a closing "/>" or a matching | |
| * end element tag. Due to the difficulties of converting incorrect HTML | |
| * to XHTML, the first option is used. | |
| */ | |
| public void addPkgDocumentation(RootDoc root, PackageDoc pd, int indent) { | |
| String rct = null; | |
| String filename = pd.name(); | |
| try { | |
| // See if the source path was specified as part of the | |
| // options and prepend it if it was. | |
| String srcLocation = null; | |
| String[][] options = root.options(); | |
| for (int opt = 0; opt < options.length; opt++) { | |
| if ((options[opt][0]).compareTo("-sourcepath") == 0) { | |
| srcLocation = options[opt][1]; | |
| break; | |
| } | |
| } | |
| filename = filename.replace('.', JDiff.DIR_SEP.charAt(0)); | |
| if (srcLocation != null) { | |
| // Make a relative location absolute | |
| if (srcLocation.startsWith("..")) { | |
| String curDir = System.getProperty("user.dir"); | |
| while (srcLocation.startsWith("..")) { | |
| srcLocation = srcLocation.substring(3); | |
| int idx = curDir.lastIndexOf(JDiff.DIR_SEP); | |
| curDir = curDir.substring(0, idx+1); | |
| } | |
| srcLocation = curDir + srcLocation; | |
| } | |
| filename = srcLocation + JDiff.DIR_SEP + filename; | |
| } | |
| // Try both ".htm" and ".html" | |
| filename += JDiff.DIR_SEP + "package.htm"; | |
| File f2 = new File(filename); | |
| if (!f2.exists()) { | |
| filename += "l"; | |
| } | |
| FileInputStream f = new FileInputStream(filename); | |
| BufferedReader d = new BufferedReader(new InputStreamReader(f)); | |
| String str = d.readLine(); | |
| // Ignore everything except the lines between <body> elements | |
| boolean inBody = false; | |
| while(str != null) { | |
| if (!inBody) { | |
| if (str.toLowerCase().trim().startsWith("<body")) { | |
| inBody = true; | |
| } | |
| str = d.readLine(); // Get the next line | |
| continue; // Ignore the line | |
| } else { | |
| if (str.toLowerCase().trim().startsWith("</body")) { | |
| inBody = false; | |
| continue; // Ignore the line | |
| } | |
| } | |
| if (rct == null) | |
| rct = str + "\n"; | |
| else | |
| rct += str + "\n"; | |
| str = d.readLine(); | |
| } | |
| } catch(java.io.FileNotFoundException e) { | |
| // If it doesn't exist, that's fine | |
| if (trace) | |
| System.out.println("No package level documentation file at '" + filename + "'"); | |
| } catch(java.io.IOException e) { | |
| System.out.println("Error reading file \"" + filename + "\": " + e.getMessage()); | |
| System.exit(5); | |
| } | |
| if (rct != null) { | |
| rct = stripNonPrintingChars(rct, (Doc)pd); | |
| rct = rct.trim(); | |
| if (rct.compareTo("") != 0 && | |
| rct.indexOf(Comments.placeHolderText) == -1 && | |
| rct.indexOf("InsertOtherCommentsHere") == -1) { | |
| int idx = endOfFirstSentence(rct); | |
| if (idx == 0) | |
| return; | |
| for (int i = 0; i < indent; i++) outputFile.print(" "); | |
| outputFile.println("<doc>"); | |
| for (int i = 0; i < indent; i++) outputFile.print(" "); | |
| String firstSentence = null; | |
| if (idx == -1) | |
| firstSentence = rct; | |
| else | |
| firstSentence = rct.substring(0, idx+1); | |
| String firstSentenceNoTags = API.stuffHTMLTags(firstSentence); | |
| outputFile.println(firstSentenceNoTags); | |
| for (int i = 0; i < indent; i++) outputFile.print(" "); | |
| outputFile.println("</doc>"); | |
| } | |
| } | |
| } | |
| /** | |
| * Find the index of the end of the first sentence in the given text, | |
| * when writing out to an XML file. | |
| * This is an extended version of the algorithm used by the DocCheck | |
| * Javadoc doclet. It checks for @tags too. | |
| * | |
| * @param text The text to be searched. | |
| * @return The index of the end of the first sentence. If there is no | |
| * end, return -1. If there is no useful text, return 0. | |
| * If the whole doc block comment is wanted (default), return -1. | |
| */ | |
| public static int endOfFirstSentence(String text) { | |
| return endOfFirstSentence(text, true); | |
| } | |
| /** | |
| * Find the index of the end of the first sentence in the given text. | |
| * This is an extended version of the algorithm used by the DocCheck | |
| * Javadoc doclet. It checks for @tags too. | |
| * | |
| * @param text The text to be searched. | |
| * @param writingToXML Set to true when writing out XML. | |
| * @return The index of the end of the first sentence. If there is no | |
| * end, return -1. If there is no useful text, return 0. | |
| * If the whole doc block comment is wanted (default), return -1. | |
| */ | |
| public static int endOfFirstSentence(String text, boolean writingToXML) { | |
| if (saveAllDocs && writingToXML) | |
| return -1; | |
| int textLen = text.length(); | |
| if (textLen == 0) | |
| return 0; | |
| int index = -1; | |
| // Handle some special cases | |
| int fromindex = 0; | |
| int ellipsis = text.indexOf(". . ."); // Handles one instance of this | |
| if (ellipsis != -1) | |
| fromindex = ellipsis + 5; | |
| // If the first non-whitespace character is an @, go beyond it | |
| int i = 0; | |
| while (i < textLen && text.charAt(i) == ' ') { | |
| i++; | |
| } | |
| if (text.charAt(i) == '@' && fromindex < textLen-1) | |
| fromindex = i + 1; | |
| // Use the brute force approach. | |
| index = minIndex(index, text.indexOf("? ", fromindex)); | |
| index = minIndex(index, text.indexOf("?\t", fromindex)); | |
| index = minIndex(index, text.indexOf("?\n", fromindex)); | |
| index = minIndex(index, text.indexOf("?\r", fromindex)); | |
| index = minIndex(index, text.indexOf("?\f", fromindex)); | |
| index = minIndex(index, text.indexOf("! ", fromindex)); | |
| index = minIndex(index, text.indexOf("!\t", fromindex)); | |
| index = minIndex(index, text.indexOf("!\n", fromindex)); | |
| index = minIndex(index, text.indexOf("!\r", fromindex)); | |
| index = minIndex(index, text.indexOf("!\f", fromindex)); | |
| index = minIndex(index, text.indexOf(". ", fromindex)); | |
| index = minIndex(index, text.indexOf(".\t", fromindex)); | |
| index = minIndex(index, text.indexOf(".\n", fromindex)); | |
| index = minIndex(index, text.indexOf(".\r", fromindex)); | |
| index = minIndex(index, text.indexOf(".\f", fromindex)); | |
| index = minIndex(index, text.indexOf("@param", fromindex)); | |
| index = minIndex(index, text.indexOf("@return", fromindex)); | |
| index = minIndex(index, text.indexOf("@throw", fromindex)); | |
| index = minIndex(index, text.indexOf("@serial", fromindex)); | |
| index = minIndex(index, text.indexOf("@exception", fromindex)); | |
| index = minIndex(index, text.indexOf("@deprecate", fromindex)); | |
| index = minIndex(index, text.indexOf("@author", fromindex)); | |
| index = minIndex(index, text.indexOf("@since", fromindex)); | |
| index = minIndex(index, text.indexOf("@see", fromindex)); | |
| index = minIndex(index, text.indexOf("@version", fromindex)); | |
| if (doExclude && excludeTag != null) | |
| index = minIndex(index, text.indexOf(excludeTag)); | |
| index = minIndex(index, text.indexOf("@vtexclude", fromindex)); | |
| index = minIndex(index, text.indexOf("@vtinclude", fromindex)); | |
| index = minIndex(index, text.indexOf("<p>", 2)); // Not at start | |
| index = minIndex(index, text.indexOf("<P>", 2)); // Not at start | |
| index = minIndex(index, text.indexOf("<blockquote", 2)); // Not at start | |
| index = minIndex(index, text.indexOf("<pre", fromindex)); // May contain anything! | |
| // Avoid the char at the start of a tag in some cases | |
| if (index != -1 && | |
| (text.charAt(index) == '@' || text.charAt(index) == '<')) { | |
| if (index != 0) | |
| index--; | |
| } | |
| /* Not used for jdiff, since tags are explicitly checked for above. | |
| // Look for a sentence terminated by an HTML tag. | |
| index = minIndex(index, text.indexOf(".<", fromindex)); | |
| if (index == -1) { | |
| // If period-whitespace etc was not found, check to see if | |
| // last character is a period, | |
| int endIndex = text.length()-1; | |
| if (text.charAt(endIndex) == '.' || | |
| text.charAt(endIndex) == '?' || | |
| text.charAt(endIndex) == '!') | |
| index = endIndex; | |
| } | |
| */ | |
| return index; | |
| } | |
| /** | |
| * Return the minimum of two indexes if > -1, and return -1 | |
| * only if both indexes = -1. | |
| * @param i an int index | |
| * @param j an int index | |
| * @return an int equal to the minimum index > -1, or -1 | |
| */ | |
| public static int minIndex(int i, int j) { | |
| if (i == -1) return j; | |
| if (j == -1) return i; | |
| return Math.min(i,j); | |
| } | |
| /** | |
| * The name of the file where the XML representing the API will be | |
| * stored. | |
| */ | |
| public static String outputFileName = null; | |
| /** | |
| * The identifier of the API being written out in XML, e.g. | |
| * "SuperProduct 1.3". | |
| */ | |
| public static String apiIdentifier = null; | |
| /** | |
| * The file where the XML representing the API will be stored. | |
| */ | |
| private static PrintWriter outputFile = null; | |
| /** | |
| * The name of the directory where the XML representing the API will be | |
| * stored. | |
| */ | |
| public static String outputDirectory = null; | |
| /** | |
| * Do not display a class with a lower level of visibility than this. | |
| * Default is to display all public and protected classes. | |
| */ | |
| public static String classVisibilityLevel = "protected"; | |
| /** | |
| * Do not display a member with a lower level of visibility than this. | |
| * Default is to display all public and protected members | |
| * (constructors, methods, fields). | |
| */ | |
| public static String memberVisibilityLevel = "protected"; | |
| /** | |
| * If set, then save the entire contents of a doc block comment in the | |
| * API file. If not set, then just save the first sentence. Default is | |
| * that this is set. | |
| */ | |
| public static boolean saveAllDocs = true; | |
| /** | |
| * If set, exclude program elements marked with whatever the exclude tag | |
| * is specified as, e.g. "@exclude". | |
| */ | |
| public static boolean doExclude = false; | |
| /** | |
| * Exclude program elements marked with this String, e.g. "@exclude". | |
| */ | |
| public static String excludeTag = null; | |
| /** | |
| * The base URI for locating necessary DTDs and Schemas. By default, this | |
| * is "https://www.w3.org". A typical value to use local copies of DTD files | |
| * might be "file:///C:/jdiff/lib" | |
| */ | |
| public static String baseURI = "https://www.w3.org"; | |
| /** | |
| * If set, then strip out non-printing characters from documentation. | |
| * Default is that this is set. | |
| */ | |
| static boolean stripNonPrintables = true; | |
| /** | |
| * If set, then add the information about the source file and line number | |
| * which is available in J2SE1.4. Default is that this is not set. | |
| */ | |
| static boolean addSrcInfo = false; | |
| /** | |
| * If set, scan classes with no packages. | |
| * If the source is a jar file this may duplicates classes, so | |
| * disable it using the -packagesonly option. Default is that this is | |
| * not set. | |
| */ | |
| static boolean packagesOnly = false; | |
| /** Set to enable increased logging verbosity for debugging. */ | |
| private static boolean trace = false; | |
| } //RootDocToXML |