$ javadoc -doclet MyDoclet -docletpath . MyClass.javaで、start() が呼ばれる
package com.mycompany.docletexam; import java.io.BufferedWriter; import java.io.File; import java.io.FileOutputStream; import java.io.IOException; import java.io.OutputStreamWriter; import java.util.Arrays; import com.sun.javadoc.ClassDoc; import com.sun.javadoc.DocErrorReporter; import com.sun.javadoc.Doclet; import com.sun.javadoc.MethodDoc; import com.sun.javadoc.Parameter; import com.sun.javadoc.RootDoc; import com.sun.javadoc.SourcePosition; import com.sun.javadoc.Type; /** * メソッド列挙 Doclet. 使い方 javadoc -encoding UTF-8 -sourcepath src/main/java -public * -doclet com.mycompany.docletexam.MethodListGenerator -docletpath * lib/MyDoclet.jar -d .\doc\summary.csv -ignore-get-set -ignore-gui * * -encodieng : ソースのエンコーディング (javadoc共通) -sourcepath : ソースの格納場所 (javadoc共通) * -public pkg1 pkg2 ... / -private pkg1 pkg2 ... : 対象パッケージ (javadoc共通) -doclet * : (必須) カスタム Docklet クラス -docletpath : (必須) カスタム Docklet が動作するために必要な Classpath * -d : (必須) 出力先 -ignore-get-set : (任意) getXXX と setXXX の組がある場合には、メソッド一覧には出力しません * -ignore-gui : (任意) java.awt.* の子孫クラスと、それらを引数・返値とするメソッドをメソッド一覧には出力しません * * ant や maven からも使えます。(サンプルは本クラスの pom.xml, build.xml) */ public class MethodListGenerator extends Doclet { /** * 処理開始 * @param rootDoc RootDoc * @return true 出力成功<br/>false 失敗 */ public static boolean start(final RootDoc rootDoc) { try { MethodListGenerator test = new MethodListGenerator(); test.printOption(rootDoc); test.printDoclet(rootDoc); System.out.println("...done"); } catch (IOException e) { e.printStackTrace(); return false; } return true; } /** * オプションの個数を返す. -d が 2 を返すほかは、com.sun.javadoc.Doclet と同じです * * @param option * @return オプションの個数 */ public static int optionLength(final String option) { if (option.matches("-d")) { return 2; } else if (option.matches("-ignore-get-set")) { return 1; } else if (option.matches("-ignore-gui")) { return 1; } return Doclet.optionLength(option); } /** * オプションの検証. * * @param options コマンドオプション * @param reporter エラー * @return true : 合格<br/>false : 不合格 */ public static boolean validOptions(final String[][] options, DocErrorReporter reporter) { // -d があったら、com.sun.javadoc.Doclet#validOptionsを呼び出す for (String[] option : options) { if ("-d".equals(option[0])) { return Doclet.validOptions(options, reporter); } } reporter.printError("-d オプションで、出力先 cvs ファイル名を指定してください"); return false; } /** * 起動オプションの表示 */ private void printOption(final RootDoc rootDoc) { System.out.println("Options:"); for (String[] param : rootDoc.options()) { System.out.format("\t%s\r\n", Arrays.toString(param)); } } /** * Docletの表示 */ private void printDoclet(final RootDoc rootDoc) throws IOException { File report = new File(findOptionValue(rootDoc, "-d")); boolean ignoreGetSet = findOptionFlag(rootDoc, "-ignore-get-set"); boolean ignoreGui = findOptionFlag(rootDoc, "-ignore-gui"); // ディレクトリを作成する File dir = report.getParentFile(); if (dir != null && !dir.exists()) { dir.mkdirs(); } // MS-Excel で開けるように MS932 で出力 BufferedWriter bw = new BufferedWriter( new OutputStreamWriter(new FileOutputStream(report), "MS932")); int no = 1; for (ClassDoc classDoc : rootDoc.classes()) { bw.write(String.format("#,\"%s\",\"\",\"%s\"\r\n", classDoc.qualifiedName(), getFirstLine(classDoc.commentText()))); if (ignoreGui && isGuiComponet(classDoc)) { continue; } for (MethodDoc methodDoc : classDoc.methods()) { //メソッド名 String methodName = methodDoc.name(); if (ignoreGetSet) { if (methodName.startsWith("get") && findSetter(classDoc, methodDoc)) { // 対抗する setter がある getter は無視する continue; } if (methodName.startsWith("set") && findGetter(classDoc, methodDoc)) { // 対抗する getter がある setter は無視する continue; } } //ソース位置 SourcePosition mtdPosition = methodDoc.position(); int mtdLine = mtdPosition.line(); //修飾子 String modifiersName = methodDoc.modifiers(); //戻り値 Type returnType = methodDoc.returnType(); if (ignoreGui && isGuiComponet(returnType.asClassDoc())) { continue; } String returnName = returnType.typeName(); if (returnType.dimension() != null) { returnName += returnType.dimension(); } //パラメータ String paramName = ""; for (Parameter parameter : methodDoc.parameters()) { if (ignoreGui && isGuiComponet(parameter.type().asClassDoc())) { continue; } paramName += "".equals(paramName) ? parameter.toString() : ", " + parameter.toString(); } bw.write( String.format("%d,\"\",\"%s %s %s(%s)\",\"%s\",%d\r\n", no++, modifiersName, returnName, methodName, paramName, getFirstLine(methodDoc.commentText()), mtdLine)); } } bw.close(); System.out.println("REPORT : " + report.getAbsolutePath()); } /** * classDoc が AWT コンポーネントを継承しているかどうかを調べます. * * @param classDoc 検査対象 * @return true : AWT コンポーネント <br/> false : AWT コンポーネントでない */ private boolean isGuiComponet(final ClassDoc classDoc) { if (classDoc == null) { return false; } if (classDoc.qualifiedName().startsWith("java.awt")) { return true; } return isGuiComponet(classDoc.superclass()); } /** * doclet のコマンドオプションにフラグ option があるかを調べます. * * @param rootDoc rootDoc * @param option 調査対象の option * @return true : あり <br/> false : なし */ private String findOptionValue(final RootDoc rootDoc, final String option) { for (String[] param : rootDoc.options()) { if (param[0].equals(option)) { return param[1]; } } return null; } /** * doclet のコマンドオプションに項目 option があるかを調べます. * * @param rootDoc rootDoc * @param option 調査対象の option * @return option の値 */ private boolean findOptionFlag(final RootDoc rootDoc, final String option) { for (String[] param : rootDoc.options()) { if (param[0].equals(option)) { return true; } } return false; } /** * Javadoc の 1行目を取得します. * * @param doc Javadoc * @return 1行目 */ private String getFirstLine(final String doc) { if (doc == null) { return ""; } // 1行目を取り出し、HTMLタグ (<br/>) があれば削除する // " は "" にする (CSVの制約) String[] parts = doc.split("[\r\n]"); return parts[0] .replaceAll("<.*>", "") .replaceAll("\"", "\"\""); } /** * setter に対応する getter があるかどうかを調べます. * * @param getter * @return */ private boolean findGetter(final ClassDoc classDoc, final MethodDoc setter) { //メソッド名 String methodName = setter.name(); return findMethod(classDoc, methodName.replace("set", "get")); } /** * getter に対応する setter があるかどうかを調べます. * * @param getter * @return */ private boolean findSetter(final ClassDoc classDoc, final MethodDoc getter) { //メソッド名 String methodName = getter.name(); return findMethod(classDoc, methodName.replace("get", "set")); } /** * class に、引数が arg で返値が ret のメソッド method があるかどうかを調べます * * @param classDoc Class * @param method メソッド名 * @return true あり<br/>false なし */ private boolean findMethod(final ClassDoc classDoc, final String method) { for (MethodDoc methodDoc : classDoc.methods()) { //メソッド名 String methodName = methodDoc.name(); if (method.equals(methodName)) { return true; } } return false; } }
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>com.mycompany.docletexam</groupId> <artifactId>doclet</artifactId> <version>0.0.1-SNAPSHOT</version> <packaging>jar</packaging> <name>doclet</name> <url>http://maven.apache.org</url> <properties> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> </properties> <dependencies> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>3.8.1</version> <scope>test</scope> </dependency> <dependency> <groupId>com.sun</groupId> <artifactId>tools</artifactId> <version>1.7</version> <scope>system</scope> <systemPath>${java.home}/../lib/tools.jar</systemPath> </dependency> </dependencies> <build> <plugins> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-site-plugin</artifactId> <version>3.3</version> <configuration> <locales>ja</locales> <inputEncoding>UTF-8</inputEncoding> <outputEncoding>UTF-8</outputEncoding> <reportPlugins> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-javadoc-plugin</artifactId> <version>2.9</version> <configuration> <doclet>com.mycompany.docletexamt.MethodListGenerator</doclet> <encoding>UTF-8</encoding> <access>private</access> <docletPath>target/doclet-0.0.1-SNAPSHOT.jar</docletPath> <additionalparam>-d doc\report.csv -ignore-get-set -ignore-gui</additionalparam> </configuration> </plugin> </reportPlugins> </configuration> </plugin> </plugins> </build> </project>
$ javadoc -doclet com.mycompany.docletexam.MethodListGenerator -docletpath target/doclet-0.0.1-SNAPSHOT.jar -sourcepath src/main/java/ -public com.mycompany.docletexam -d summary.csv
pom.xml からも実行できる (使用例は MethodListGenerator? の pom.xml)