package edu.pdx.cs410J.grader; import com.sun.javadoc.*; import java.io.*; import java.text.BreakIterator; /** * This <A * href="http://java.sun.com/j2se/1.4.2/docs/tooldocs/javadoc/overview.html">doclet</A> * extracts the API documentation (Javadocs) * from a student's project submission and produces a text summary of * them. It is used for grading a student's Javadocs. * * @author David Whitlock * @since Summer 2004 */ @SuppressWarnings("UnusedDeclaration") public class APIDocumentationDoclet { /** * NOTE: Without this method present and returning LanguageVersion.JAVA_1_5, * Javadoc will not process generics because it assumes LanguageVersion.JAVA_1_1. * * Note that 1.5 is as high as the <code>LanguageVersion</code> goes. * * @return language version (hard coded to LanguageVersion.JAVA_1_5) */ public static LanguageVersion languageVersion() { return LanguageVersion.JAVA_1_5; } /** * This doclet has no valid options */ public static boolean validOptions(String[][] options, DocErrorReporter reporter) { return true; } /** * Since there are no options, we always return zero. */ public static int optionLength(String option) { return 0; } /** * Print out a summary of each class, field, and method to standard * out. */ public static boolean start(RootDoc root) { PrintWriter pw = new PrintWriter(System.out, true); ClassDoc[] classes = root.classes(); for (ClassDoc aClass : classes) { generate(aClass, pw); pw.println(""); } return true; } /** * Indents a block of text a given amount. */ private static void indent(String text, final int indent, PrintWriter pw) { StringBuilder sb = new StringBuilder(); for (int i = 0; i < indent; i++) { sb.append(" "); } String spaces = sb.toString(); pw.print(spaces); int printed = indent; boolean firstWord = true; BreakIterator boundary = BreakIterator.getWordInstance(); boundary.setText(text); int start = boundary.first(); for (int end = boundary.next(); end != BreakIterator.DONE; start = end, end = boundary.next()) { String word = text.substring(start, end); if (printed + word.length() > 72) { pw.println(""); pw.print(spaces); printed = indent; firstWord = true; } if (word.charAt(word.length() - 1) == '\n') { pw.write(word, 0, word.length() - 1); } else if (firstWord && Character.isWhitespace(word.charAt(0))) { pw.write(word, 1, word.length() - 1); } else { pw.print(word); } printed += (end - start); firstWord = false; } pw.println(""); } /** * Generates a summary of the API documentation for a given class */ private static void generate(ClassDoc c, PrintWriter pw) { pw.println("Class " + c.qualifiedTypeName()); indent(c.commentText(), 2, pw); pw.println(""); ConstructorDoc[] constructors = c.constructors(); for (ConstructorDoc constructor : constructors) { generate(constructor, pw); } MethodDoc[] methods = c.methods(); for (MethodDoc method : methods) { generate(method, pw); } } /** * Generates a summary of the API documentation for a method or * constructor */ private static void generate(ExecutableMemberDoc m, PrintWriter pw) { StringBuilder sb = new StringBuilder(); sb.append(m.modifiers()).append(" "); appendTypeVariables(m.typeParameters(), sb); appendReturnType(m, sb); sb.append(m.name()); sb.append("("); Parameter[] params = m.parameters(); for (int i = 0; i < params.length; i++) { Parameter param = params[i]; sb.append(param.typeName()); sb.append(" "); sb.append(param.name()); if (i < params.length - 1) { sb.append(", "); } } sb.append(")"); indent(sb.toString(), 2, pw); String comment = m.commentText(); if (comment != null && !comment.equals("")) { indent(comment, 4, pw); } pw.println(""); ParamTag[] tags = m.paramTags(); for (ParamTag tag : tags) { indent(tag.parameterName() + " - " + tag.parameterComment(), 4, pw); pw.println(""); } ThrowsTag[] throwsTags = m.throwsTags(); for (ThrowsTag tag : throwsTags) { indent("throws " + tag.exceptionName() + " - " + tag.exceptionComment(), 4, pw); pw.println(""); } } private static void appendTypeVariables(TypeVariable[] variables, StringBuilder sb) { if (variables.length > 0) { sb.append("<"); for (int i = 0; i < variables.length; i++) { TypeVariable variable = variables[i]; appendType(variable, sb); if (i < variables.length - 1) { sb.append(", "); } } sb.append("> "); } } private static void appendReturnType(ExecutableMemberDoc m, StringBuilder sb) { if (m instanceof MethodDoc) { MethodDoc method = (MethodDoc) m; appendType(method.returnType(), sb).append(" "); } } private static StringBuilder appendType(Type type, StringBuilder sb) { sb.append(type.qualifiedTypeName()); ParameterizedType parameterizedType = type.asParameterizedType(); if (parameterizedType != null) { appendTypeArguments(parameterizedType.typeArguments(), sb); } return sb; } private static void appendTypeArguments(Type[] typeArguments, StringBuilder sb) { if (typeArguments.length >0) { sb.append("<"); for (int i = 0; i < typeArguments.length; i++) { Type typeArgument = typeArguments[i]; sb.append(typeArgument.qualifiedTypeName()); if (i < typeArguments.length - 1) { sb.append(", "); } } sb.append(">"); } } }