Java tutorial
package jdiff; import java.io.*; import java.util.*; import org.apache.commons.lang3.StringEscapeUtils; /** * The internal representation of an API. * * RootDoc could have been used for representing this, but * you cannot serialize a RootDoc object - see * http://developer.java.sun.com/developer/bugParade/bugs/4125581.html * You might be able use Javadoc.Main() to create another RootDoc, but the * methods are package private. You can run javadoc in J2SE1.4, see: * http://java.sun.com/j2se/1.4/docs/tooldocs/javadoc/standard-doclet.html#runningprogrammatically * but you still can't get the RootDoc object. * * The advantage of writing out an XML representation of each API is that * later runs of JDiff don't have to have Javadoc scan all the files again, * a possibly lengthy process. XML also permits other source code in * languages other than Java to be scanned to produce XML, and then versions * of JDiff can be used to create documents describing the difference in those * APIs. * * See the file LICENSE.txt for copyright details. * @author Matthew Doar, mdoar@pobox.com */ public class API { /** * The list of all the top-level packages. * Each package contains classes, each class contains members, and so on. */ public List packages_; // PackageAPI[] /** * The list of all the classes. * This is used to generate the methods and fields which are inherited, * rather than storing them in the XML file. */ public Hashtable classes_; /** * The String which identifies this API, e.g. "SuperProduct 1.3". */ public String name_ = null; /** The current package being added to during parsing. */ public PackageAPI currPkg_ = null; /** The current class being added to during parsing. */ public ClassAPI currClass_ = null; /** The current constructor being added to during parsing. */ public ConstructorAPI currCtor_ = null; /** The current method being added to during parsing. */ public MethodAPI currMethod_ = null; /** The current field being added to during parsing. */ public FieldAPI currField_ = null; /** Default constructor. */ public API() { packages_ = new ArrayList(); //PackageAPI[] classes_ = new Hashtable(); //ClassAPI } // // Methods to display the contents of an API object. // /** Amount by which to increment each indentation. */ public static final int indentInc = 2; /** Display the contents of the API object. */ public void dump() { int indent = 0; Iterator iter = packages_.iterator(); while (iter.hasNext()) { dumpPackage((PackageAPI) (iter.next()), indent); } } /** * Display the contents of a PackageAPI object. * * @param pkg The given PackageAPI object. * @param indent The number of spaces to indent the output. */ public void dumpPackage(PackageAPI pkg, int indent) { for (int i = 0; i < indent; i++) System.out.print(" "); System.out.println("Package Name: " + pkg.name_); Iterator iter = pkg.classes_.iterator(); while (iter.hasNext()) { dumpClass((ClassAPI) (iter.next()), indent + indentInc); } // Display documentation if (pkg.doc_ != null) { System.out.print("Package doc block:"); System.out.println("\"" + pkg.doc_ + "\""); } } /** * Display the contents of a ClassAPI object. * * @param c The given ClassAPI object. * @param indent The number of spaces to indent the output. */ public static void dumpClass(ClassAPI c, int indent) { for (int i = 0; i < indent; i++) System.out.print(" "); if (c.isInterface_) System.out.println("Interface name: " + c.name_); else System.out.println("Class Name: " + c.name_); if (c.extends_ != null) { for (int i = 0; i < indent; i++) System.out.print(" "); System.out.println("Extends: " + c.extends_); } if (c.implements_.size() != 0) { for (int i = 0; i < indent; i++) System.out.print(" "); System.out.println("Implements: "); Iterator iter = c.implements_.iterator(); while (iter.hasNext()) { String interfaceImpl = (String) (iter.next()); for (int i = 0; i < indent + 2; i++) System.out.print(" "); System.out.println(" " + interfaceImpl); } } // Dump modifiers specific to a class if (c.isAbstract_) System.out.print("abstract "); // Dump modifiers common to all dumpModifiers(c.modifiers_, indent); // Dump ctors Iterator iter = c.ctors_.iterator(); while (iter.hasNext()) { dumpCtor((ConstructorAPI) (iter.next()), indent + indentInc); } // Dump methods iter = c.methods_.iterator(); while (iter.hasNext()) { dumpMethod((MethodAPI) (iter.next()), indent + indentInc); } // Dump fields iter = c.fields_.iterator(); while (iter.hasNext()) { dumpField((FieldAPI) (iter.next()), indent + indentInc); } // Display documentation if (c.doc_ != null) { System.out.print("Class doc block:"); System.out.println("\"" + c.doc_ + "\""); } else System.out.println(); } /** * Display the contents of the Modifiers object. * * @param c The given Modifiers object. * @param indent The number of spaces to indent the output. */ public static void dumpModifiers(Modifiers m, int indent) { for (int i = 0; i < indent; i++) System.out.print(" "); if (m.isStatic) System.out.print("static "); if (m.isFinal) System.out.print("final "); if (m.visibility != null) System.out.print("visibility = " + m.visibility + " "); // Flush the line System.out.println(); } /** * Display the contents of a constructor. * * @param c The given constructor object. * @param indent The number of spaces to indent the output. */ public static void dumpCtor(ConstructorAPI c, int indent) { for (int i = 0; i < indent; i++) System.out.print(" "); System.out.println("Ctor type: " + getShortName(c.type_)); // Display exceptions System.out.print("exceptions: " + c.exceptions_ + " "); // Dump modifiers common to all dumpModifiers(c.modifiers_, indent); // Display documentation if (c.doc_ != null) { System.out.print("Ctor doc block:"); System.out.println("\"" + c.doc_ + "\""); } } /** * Display the contents of a MethodAPI object. * * @param m The given MethodAPI object. * @param indent The number of spaces to indent the output. */ public static void dumpMethod(MethodAPI m, int indent) { if (m.inheritedFrom_ != null) return; for (int i = 0; i < indent; i++) System.out.print(" "); System.out.print("Method Name: " + m.name_); if (m.inheritedFrom_ != null) System.out.println(", inherited from: " + m.inheritedFrom_); if (m.returnType_ != null) System.out.println(", return type: " + m.returnType_); else System.out.println(); // Dump modifiers specific to a method if (m.isAbstract_) System.out.print("abstract "); if (m.isNative_) System.out.print("native "); if (m.isSynchronized_) System.out.print("synchronized "); // Display exceptions System.out.print("exceptions: " + m.exceptions_ + " "); // Dump modifiers common to all dumpModifiers(m.modifiers_, indent); Iterator iter = m.params_.iterator(); while (iter.hasNext()) { dumpParam((ParamAPI) (iter.next()), indent + indentInc); } // Display documentation if (m.doc_ != null) { System.out.print("Method doc block:"); System.out.println("\"" + m.doc_ + "\""); } } /** * Display the contents of a field. * Does not show inherited fields. * * @param f The given field object. * @param indent The number of spaces to indent the output. */ public static void dumpField(FieldAPI f, int indent) { if (f.inheritedFrom_ != null) return; for (int i = 0; i < indent; i++) System.out.print(" "); System.out.println("Field Name: " + f.name_ + ", type: " + f.type_); if (f.inheritedFrom_ != null) System.out.println(", inherited from: " + f.inheritedFrom_); if (f.isTransient_) System.out.print("transient "); if (f.isVolatile_) System.out.print("volatile "); // Dump modifiers common to all dumpModifiers(f.modifiers_, indent); // Display documentation if (f.doc_ != null) System.out.print("Field doc block:"); System.out.println("\"" + f.doc_ + "\""); } /** * Display the contents of a parameter. * * @param p The given parameter object. * @param indent The number of spaces to indent the output. */ public static void dumpParam(ParamAPI p, int indent) { for (int i = 0; i < indent; i++) System.out.print(" "); System.out.println("Param Name: " + p.name_ + ", type: " + p.type_); } /** * Convert all HTML tags to text by placing them inside a CDATA element. * Characters still have to be valid Unicode characters as defined by the * parser. */ public static String stuffHTMLTags(String htmlText) { if (htmlText.indexOf("]]>") != -1) { System.out.println("Warning: illegal string ]]> found in text. Ignoring the comment."); return ""; } return "<![CDATA[" + htmlText + "]]>"; } /** * Convert all HTML tags to text by stuffing text into the HTML tag * to stop it being an HTML or XML tag. E.g. "<code>foo</code>" * becomes "lEsS_tHaNcode>foolEsS_tHaN/code>". Replace all < * characters * with the string "lEsS_tHaN". Also replace & character with the * string "aNd_cHaR" to avoid text entities. Also replace " * character with the * string "qUoTe_cHaR". */ public static String hideHTMLTags(String htmlText) { StringBuffer sb = new StringBuffer(htmlText); int i = 0; while (i < sb.length()) { if (sb.charAt(i) == '<') { sb.setCharAt(i, 'l'); sb.insert(i + 1, "EsS_tHaN"); } else if (sb.charAt(i) == '&') { sb.setCharAt(i, 'a'); sb.insert(i + 1, "Nd_cHaR"); } else if (sb.charAt(i) == '"') { sb.setCharAt(i, 'q'); sb.insert(i + 1, "uote_cHaR"); } i++; } return sb.toString(); } /** * Convert text with stuffed HTML tags ("lEsS_tHaN", etc) into HTML text. */ public static String showHTMLTags(String text) { StringBuffer sb = new StringBuffer(text); StringBuffer res = new StringBuffer(); int len = sb.length(); res.setLength(len); int i = 0; int resIdx = 0; while (i < len) { char c = sb.charAt(i); if (len - i > 8 && c == 'l' && sb.charAt(i + 1) == 'E' && sb.charAt(i + 2) == 's' && sb.charAt(i + 3) == 'S' && sb.charAt(i + 4) == '_' && sb.charAt(i + 5) == 't' && sb.charAt(i + 6) == 'H' && sb.charAt(i + 7) == 'a' && sb.charAt(i + 8) == 'N') { res.setCharAt(resIdx, '<'); i += 8; } else if (len - i > 9 && c == 'q' && sb.charAt(i + 1) == 'U' && sb.charAt(i + 2) == 'o' && sb.charAt(i + 3) == 'T' && sb.charAt(i + 4) == 'e' && sb.charAt(i + 5) == '_' && sb.charAt(i + 6) == 'c' && sb.charAt(i + 7) == 'H' && sb.charAt(i + 8) == 'a' && sb.charAt(i + 9) == 'R') { res.setCharAt(resIdx, '"'); i += 9; } else if (len - i > 7 && c == 'a' && sb.charAt(i + 1) == 'N' && sb.charAt(i + 2) == 'd' && sb.charAt(i + 3) == '_' && sb.charAt(i + 4) == 'c' && sb.charAt(i + 5) == 'H' && sb.charAt(i + 6) == 'a' && sb.charAt(i + 7) == 'R') { res.setCharAt(resIdx, '&'); i += 7; } else { res.setCharAt(resIdx, c); } i++; resIdx++; } res.setLength(resIdx); return res.toString(); } /** * <b>NOT USED</b>. * * Replace all instances of <p> with <p/>. Just for the small number * of HMTL tags which don't require a matching end tag. * Also make HTML conform to the simple HTML requirements such as * no double hyphens. Double hyphens are replaced by - and the character * entity for a hyphen. * * Cases where this fails and has to be corrected in the XML by hand: * Attributes' values missing their double quotes , e.g. size=-2 * Mangled HTML tags e.g. <ttt> * * <p><b>NOT USED</b>. There is often too much bad HTML in * doc blocks to try to handle every case correctly. Better just to * stuff the *lt; and &: characters with stuffHTMLTags(). Though * the resulting XML is not as elegant, it does the job with less * intervention by the user. */ public static String convertHTMLTagsToXHTML(String htmlText) { StringBuffer sb = new StringBuffer(htmlText); int i = 0; boolean inTag = false; String tag = null; // Needs to re-evaluate this length at each loop while (i < sb.length()) { char c = sb.charAt(i); if (inTag) { if (c == '>') { // OPTION Could fail at or fix some errorneous tags here // Make the best guess as to whether this tag is terminated if (Comments.isMinimizedTag(tag) && htmlText.indexOf("</" + tag + ">", i) == -1) sb.insert(i, "/"); inTag = false; } else { // OPTION could also make sure that attribute values are // surrounded by quotes. tag += c; } } if (c == '<') { inTag = true; tag = ""; } // -- is not allowed in XML, but !-- is part of an comment, // and --> is also part of a comment if (c == '-' && i > 0 && sb.charAt(i - 1) == '-') { if (!(i > 1 && sb.charAt(i - 2) == '!')) { sb.setCharAt(i, '&'); sb.insert(i + 1, "#045;"); i += 5; } } i++; } if (inTag) { // Oops. Someone forgot to close their HTML tag, e.g. "<code." // Close it for them. sb.insert(i, ">"); } return sb.toString(); } public void dumpPackagesAtClassLevel(PrintWriter writer) { // TODO Auto-generated method stub Iterator iter = packages_.iterator(); while (iter.hasNext()) { dumpPackageAtClassLevel((PackageAPI) (iter.next()), writer); } } private void dumpPackageAtClassLevel(PackageAPI packageAPI, PrintWriter writer) { // writer.println("Package Name: " + packageAPI.name_); // Display documentation if (packageAPI.doc_ != null) { // writer.println("\"" + packageAPI.doc_ + "\""); } Iterator iter = packageAPI.classes_.iterator(); int index = 1; while (iter.hasNext()) { dumpClass((ClassAPI) (iter.next()), writer, packageAPI.name_); index++; } } private void dumpClass(ClassAPI c, PrintWriter writer, String packageName) { if (c.isInterface_) writer.println(packageName + "." + c.name_); else writer.println(packageName + "." + c.name_); if (c.doc_ != null) { writer.println(c.doc_); } } public void dumpPackagesAtMethodLevel(PrintWriter writer) { Iterator iter = packages_.iterator(); while (iter.hasNext()) { dumpPackageAtMethodLevel((PackageAPI) (iter.next()), writer); } } private void dumpPackageAtMethodLevel(PackageAPI packageAPI, PrintWriter writer) { // TODO Auto-generated method stub if (packageAPI.doc_ != null) { // writer.println("\"" + packageAPI.doc_ + "\""); } Iterator iter = packageAPI.classes_.iterator(); int index = 1; while (iter.hasNext()) { writer.println("------------------------------------------------------------------------------------"); dumpClassAtMethodLevel((ClassAPI) (iter.next()), writer, packageAPI.name_); index++; } } private void dumpClassAtMethodLevel(ClassAPI classAPI, PrintWriter writer, String packageName) { writer.println("package " + packageName + ";"); if (classAPI.isInterface_) writer.println("public interface " + classAPI.name_ + "{"); else { writer.print("public "); if (classAPI.modifiers_.isStatic) writer.print("static "); if (classAPI.modifiers_.isFinal) writer.print("final "); if (classAPI.isAbstract_) { writer.println("abstract "); } writer.print("class " + classAPI.name_); if ((classAPI.extends_ != null) && (!classAPI.extends_.isEmpty()) && (!classAPI.extends_.equals("java.lang.Object"))) { writer.print(" extends "); writer.print(classAPI.extends_ + " "); } if (classAPI.implements_.size() != 0) { writer.println(" implements "); Iterator iter = classAPI.implements_.iterator(); int index = 0; while (iter.hasNext()) { String interfaceImpl = (String) (iter.next()); if (index > 0) { writer.print(", "); } writer.print(interfaceImpl); index++; } } writer.println(" {"); } // Dump ctors Iterator iter = classAPI.ctors_.iterator(); while (iter.hasNext()) { dumpCtor((ConstructorAPI) (iter.next()), classAPI.name_, writer); } // Dump methods iter = classAPI.methods_.iterator(); while (iter.hasNext()) { dumpMethod((MethodAPI) (iter.next()), writer); } // Dump fields iter = classAPI.fields_.iterator(); while (iter.hasNext()) { dumpField((FieldAPI) (iter.next()), writer); } writer.println("}"); } private void dumpField(FieldAPI f, PrintWriter writer) { } private void dumpMethod(MethodAPI m, PrintWriter writer) { if (m.inheritedFrom_ != null) return; writer.print(" public "); if (m.modifiers_.isStatic) writer.print("static "); if (m.modifiers_.isFinal) writer.print("final "); // Dump modifiers specific to a method if (m.isAbstract_) System.out.print(" abstract"); if (m.isNative_) System.out.print(" native"); if (m.isSynchronized_) System.out.print(" synchronized"); if (m.returnType_ != null) writer.print(getShortName(m.returnType_)); else writer.print(" void "); writer.print(" " + m.name_); writer.print("("); Iterator iter = m.params_.iterator(); int index = 0; while (iter.hasNext()) { if (index > 0) { writer.print(", "); } dumpParam((ParamAPI) (iter.next()), writer); index++; } writer.print(")"); // Display exceptions // if ((m.exceptions_!= null) && (!m.exceptions_.isEmpty()) && (!m.exceptions_.equals("no exceptions"))) //{ // writer.print(" throws " + m.exceptions_ + " "); //} writer.println(" {}"); } private void dumpParam(ParamAPI p, PrintWriter writer) { writer.print(getShortName(p.type_) + " " + p.name_); } private static String getShortName(String fullyQualifiedName) { String shortName = fullyQualifiedName; for (int i = fullyQualifiedName.length() - 1; i >= 0; i--) { String c = fullyQualifiedName.substring(i, i + 1); if (c.equals(".")) { shortName = fullyQualifiedName.substring(i + 1, fullyQualifiedName.length()); break; } } System.out.println(String.format("%s is shortened to %s", fullyQualifiedName, shortName)); return shortName; } private void dumpCtor(ConstructorAPI c, String className, PrintWriter writer) { writer.print(" public " + getShortName(c.type_) + " "); if (c.modifiers_.isStatic) writer.print("static "); if (c.modifiers_.isFinal) writer.print("final "); writer.print(className); writer.print("("); writer.print(")"); if ((c.exceptions_ != null) && (!c.exceptions_.isEmpty()) && (!c.exceptions_.equals("no exceptions"))) { writer.print(" throws " + c.exceptions_ + " "); } writer.println(" {}"); } public void dumpPackagesAtClassLevelInCsvFormat(PrintWriter writer) { Iterator iter = packages_.iterator(); while (iter.hasNext()) { dumpPackageAtClassLevelInCsvFormat((PackageAPI) (iter.next()), writer); } } private void dumpPackageAtClassLevelInCsvFormat(PackageAPI packageAPI, PrintWriter writer) { writer.println(packageAPI.name_); // Display documentation if (packageAPI.doc_ != null) { // writer.println("\"" + packageAPI.doc_ + "\""); } Iterator iter = packageAPI.classes_.iterator(); int index = 1; while (iter.hasNext()) { dumpClassInCsvFormat((ClassAPI) (iter.next()), writer); index++; } } private void dumpClassInCsvFormat(ClassAPI classAPI, PrintWriter writer) { if (classAPI.isInterface_) writer.print(classAPI.name_); else writer.print(classAPI.name_); if (classAPI.doc_ != null) { writer.println(", " + StringEscapeUtils.escapeCsv(removeNewLine(classAPI.doc_))); } else { writer.println(); } } private String removeNewLine(String sourceString) { String resultString = sourceString.replace("\n", " ").replace("\r", " "); return resultString; } public void dumpPackagesAtClassLevelBrief(PrintWriter writer) { Iterator iter = packages_.iterator(); while (iter.hasNext()) { dumpPackageAtClassLevelBrief((PackageAPI) (iter.next()), writer); } } private void dumpPackageAtClassLevelBrief(PackageAPI packageAPI, PrintWriter writer) { Iterator iter = packageAPI.classes_.iterator(); int index = 1; while (iter.hasNext()) { writer.println(packageAPI.name_ + ((ClassAPI) (iter.next())).name_); } } }