ドックレットの概要

目次

ドックレットの基本

ドックレットとは、Javaプログラミング言語で記述したプログラムのうち、ドックレットAPIを使用してJavadocツールの内容と出力形式を指定したものです。Javadocツールのデフォルトでは、HTML形式のAPIドキュメントを生成するための、Oracleが提供した「標準」ドックレットが使用されます。しかし、独自のドックレットを作成してJavadocの出力を好みの形式にカスタマイズすることもできます。ドックレットは、ドックレットAPIを使用してゼロから作成することも、必要に応じて標準ドックレットに手を加える形で作成することもできます。

ドックレットは、次の基本手順に従って作成し、使用します。

  1. ドックレットとなるJavaプログラムを記述します。ドックレットAPIを使用するためには、com.sun.javadoc.*をインポートする必要があります。作成したプログラムのエントリ・ポイントは、public static boolean startメソッドのあるクラスです。そのメソッドは、パラメータとしてRootDocを取ります。
  2. ドックレットをコンパイルします。コンパイルには、Java 2 SDKに含まれるコンパイラjavacを使用できます。
  3. -doclet startingclass オプションを指定してJavadocツールを実行し、作成したドックレットが指定する出力を生成します。ここで、startingclassは、手順1で説明した開始クラスの完全指定の名前です。
ドックレットAPIのクラス・ファイルは、SDKのlib/tools.jarファイルに含まれています。ドックレットをコンパイルするときは、tools.jarがクラス・パスに存在する必要があります。このような場合は、javacの-classpathオプションを使用できます。

コマンド行オプション-docletを指定せずにjavadocを実行した場合は、デフォルトでHTML形式のAPIドキュメントを生成する標準ドックレットが使用されます。

com.sun.javadocパッケージは、ドックレットAPIを定義するいくつかのインタフェースで構成されています。これらのインタフェースは、Java 2 SDKのlib/tools.jarファイルに含まれています。このファイルには、これらのインタフェースを実装するクラスが含まれるprivateパッケージも入っています。さらに、tools.jarファイルには、標準ドックレットを実装したクラスも含まれています。

簡単なドックレットの例

次に、小さなクラスが1つだけ含まれる簡単なドックレットの例を示します。この例を見れば、ドックレットの仕組みについて感触をつかめるはずです。
import com.sun.javadoc.*;

public class ListClass {
    public static boolean start(RootDoc root) {
        ClassDoc[] classes = root.classes();
        for (int i = 0; i < classes.length; ++i) {
            System.out.println(classes[i]);
        }
        return true;
    }
}
コードから推察できるように、このドックレットは、javadocの処理対象となるクラスについて、その名前を標準出力に書き出します。

ドックレットに関して最初に注意するべき点は、ドックレットAPIを使用できるようにするためにcom.sun.javadocパッケージをインポートしなければならないということです。エントリ・ポイントは、どのドックレットの場合にもpublic static boolean startメソッドです。startメソッドは、パラメータとしてRootDocを取ります。このパラメータには、javadocの実行時にコマンド行に指定されたオプションと、javadocの処理対象となるクラスとパッケージについての情報が入っています。

RootDocは、classesというメソッドを定義しています。このメソッドからは、ClassDoc配列が返されますが、この配列の要素はjavadocが解析するクラスを表しています。次に、forループで、配列に含まれる各クラスの名前を出力します。ClassDocをprintlnに引き渡すと、ClassDocが表しているクラスの名前が出力されます。

このドックレットを実行するには、まずコンパイルする必要があります。コンパイルは、javacコンパイラで行います。ドックレットAPIのクラス・ファイルはJava 2 SDKのlib/tools.jarファイルに含まれていますが、javacはこのクラス・ファイルを自動的にはロードしません。このため、次の例のようにして、コンパイラのclasspathにtools.jarを含める必要があります。

javac -classpath C:\jdk1.3\lib\tools.jar ListClass.java 
ListClassドックレットを実行するには、コンパイルしたドックレットをjavadocの-docletおよび-docletpathタグで指定します。たとえば、このドックレットをMyClass.javaというファイルに対して実行するには、次のコマンドを使用します(ListClass.classが現在のディレクトリ内にあると想定)。
% javadoc -doclet ListClass -docletpath .  MyClass.java
出力は、「MyClass」という文字列になります。このコマンドを使用するとき、tools.jarをクラス・パス上に置く必要はありません。そのファイルは、Javadocツールが自動的にロードするからです。

コマンド行オプションについての注: javadoc -helpを実行するとわかるように、Javadocツールにはコマンド行オプションが2セットあります。一方のセットは汎用で、どのドックレットでも使用できます。もう一方のオプションのセットは、標準ドックレット専用です。この2番目のオプションのセットは、カスタム・ドックレットを使う場合には利用できません。カスタム・ドックレットでは、ドックレット独自のコマンド行オプションを定義することもできます。このあとのを参照してください。

APIドキュメントを生成するには、ドックレットは、この簡単な例よりもかなり複雑になります。javadocで生成するAPIドキュメントの形式をカスタマイズする場合は、ドックレットを自分でゼロから作成するよりも、デフォルトの標準ドックレットに修正を加える形で作成した方が簡単です。

例 - 標準ドックレットのサブクラス化

Javadocツールの出力をカスタマイズするには、必要な出力の内容と形式を指定する独自のドックレットを作成する必要があります。デフォルトの出力とほぼ同じ形式のHTML出力が必要な場合は、ドックレット作成の出発点として、標準ドックレットを利用すると便利です。標準ドックレットに含まれる適切なクラスをサブクラス化し、必要な出力が生成されるようにメソッドを追加またはオーバーライドします。あるいは、標準ドックレット全体をコピーして、それに修正を加えていくという方法もあります。標準ドックレットのコピーを出発点として使用する場合は、必要に応じて、各ソース・ファイルの先頭にあるpackage文を削除し、新しい独自のパッケージ名に置き換えてください。

実例は、「How can I modify the standard doclet to produce links to source code from the API documentation?」を参照してください。

例 - カスタム・タグの作成と処理

ドキュメンテーション・コメントの中で、@param@returnなどの標準タグに加えて、カスタム・タグ(@mytag)を使用する場合について考えてみます。カスタム・タグの中の情報を使用するには、そのカスタム・タグを表すTagのインスタンスをドックレットで使用する必要があります。このためのもっとも簡単な方法の1つは、DocまたはDocのサブクラスのtags(String)メソッドを使用することです。このメソッドは、名前がString引数に一致するすべてのタグを含むTagオブジェクトの配列を返します。たとえば、methodMethodDocのインスタンスである場合、コードは次のようになります。
method.tags("mytag")
このコードは、メソッドのドキュメンテーション・コメントに含まれるすべての@mytagを表すTagオブジェクトの配列を返します。@mytagタグ内の情報へは、Tagtextメソッドを使用すればアクセスできます。このメソッドは、タグの内容を表す文字列を返すので、用途に応じてこの文字列を解析したり使用したりできます。たとえば、ドキュメンテーション・コメントに、次のようなカスタム・タグが含まれているとします。
@mytag Some dummy text.
この場合、textメソッドは、「Some dummy text.」という文字列を返します。

次に示すコードは、これまで説明した考え方を使用して、メソッドのコメント内に見つかるタグのうち、指定されたタグのすべてのインスタンスに関連付けられたテキストを表示するスタンドアロン・ドックレットです。これは標準ドックレットのサブクラスではありません。このドックレットは、すべてのコメントに含まれるそのタグのすべてのインスタンスを検出するように拡張できます。

import com.sun.javadoc.*;

public class ListTags {
    public static boolean start(RootDoc root){ 
        String tagName = "mytag";
        writeContents(root.classes(), tagName);
        return true;
    }

    private static void writeContents(ClassDoc[] classes, String tagName) {
        for (int i=0; i < classes.length; i++) {
            boolean classNamePrinted = false;
            MethodDoc[] methods = classes[i].methods();
            for (int j=0; j < methods.length; j++) {
                Tag[] tags = methods[j].tags(tagName);
                if (tags.length > 0) {
                    if (!classNamePrinted) {
                        System.out.println("\n" + classes[i].name() + "\n");
                        classNamePrinted = true;
                    }
                    System.out.println(methods[j].name());
                    for (int k=0; k < tags.length; k++) {
                        System.out.println("   " + tags[k].name() + ": " 
                            + tags[k].text());
                    }
                } 
            }
        }
    }
}
このドックレットが検索するタグは、変数tagNameによって指定されています。tagNameには、カスタム・タグでも標準タグでも、任意のタグの名前を指定できます。このドックレットは結果を標準出力に出力しますが、出力の形式は変更可能です。たとえば、HTML形式の出力をファイルに書き込むことができます。

例 - カスタム・コマンド行オプションの使用

カスタムのコマンド行オプションでドックレットを作成することもできます。ここでは、検索するタグの名前をコマンド行オプションで指定できるように、上記のドックレットを拡張します。

カスタム・オプションを使用するドックレットには、int型の値を返すoptionLength(String option)というメソッドが必要です。optionLengthは、ドックレットが認識するカスタム・オプションごとに、そのオプションを構成する要素(トークン)の数を返さなければなりません。ここでは、-tag mytagという形式のカスタム・オプションを使用できるようにしてみます。このカスタム・オプションは-tagオプションそのものとその値という2つの要素で構成されるので、作成するドックレットのoptionLengthメソッドは、-tagオプションに対して2を返さなければなりません。また、optionsLengthメソッドでは、認識できないオプションに対して0を返すようにします。

拡張を施したドックレットの完全なコードを次に示します。

import com.sun.javadoc.*;

public class ListTags {
    public static boolean start(RootDoc root){ 
        String tagName = readOptions(root.options());
        writeContents(root.classes(), tagName);
        return true;
    }

    private static void writeContents(ClassDoc[] classes, String tagName) {
        for (int i=0; i < classes.length; i++) {
            boolean classNamePrinted = false;
            MethodDoc[] methods = classes[i].methods();
            for (int j=0; j < methods.length; j++) {
                Tag[] tags = methods[j].tags(tagName);
                if (tags.length > 0) {
                    if (!classNamePrinted) {
                        System.out.println("\n" + classes[i].name() + "\n");
                        classNamePrinted = true;
                    }
                    System.out.println(methods[j].name());
                    for (int k=0; k < tags.length; k++) {
                        System.out.println("   " + tags[k].name() + ": " + tags[k].text());
                    }
                } 
            }
        }
    }

    private static String readOptions(String[][] options) {
        String tagName = null;
        for (int i = 0; i < options.length; i++) {
            String[] opt = options[i];
            if (opt[0].equals("-tag")) {
                tagName = opt[1];
            }
        }
        return tagName;
    }

    public static int optionLength(String option) {
        if(option.equals("-tag")) {
            return 2;
        }
        return 0;
    }

    public static boolean validOptions(String options[][], 
                                       DocErrorReporter reporter) {
        boolean foundTagOption = false;
        for (int i = 0; i < options.length; i++) {
            String[] opt = options[i];
            if (opt[0].equals("-tag")) {
                if (foundTagOption) {
                    reporter.printError("Only one -tag option allowed.");
                    return false;
                } else { 
                    foundTagOption = true;
                }
            } 
        }
        if (!foundTagOption) {
            reporter.printError("Usage: javadoc -tag mytag -doclet ListTags ...");
        }
        return foundTagOption;
    }
}
修正が加えられたこのドックレットでは、変数tagNameを、コマンド行オプション-tagで設定するようになっています。また、このカスタム・オプションに対して2を返すoptionLengthメソッドが用意されています。なお、optionLengthを明示的に呼び出す必要はありません。

さらに、このドックレットには、コマンド行オプションを解析して-tagオプションを探すreadOptionsメソッドも追加されています。このメソッドでは、オプションの情報が含まれたString型の2次元配列を返すRootdoc.optionsメソッドを利用しています。たとえば、次のコマンドを実行するとします。

javadoc -foo this that -bar other ...
RootDoc.optionsメソッドは次の戻り値を返します。
options()[0][0] = "-foo"
options()[0][1] = "this"
options()[0][2] = "that"
options()[1][0] = "-bar"
options()[1][1] = "other"
配列の2番目の添え字に入っている要素数は、optionLengthメソッドにより判別されます。この例では、optionLength-fooオプションに対して3を返し、-barオプションに対して2を返します。

validOptionsメソッドは、コマンド行タグの指定が正しいかどうかをチェックするための、省略可能なメソッドです。validOptionsメソッドは、存在すれば自動的に呼び出されるため、明示的に呼び出す必要はありません。このメソッドでは、オプションの指定が正しい場合はtrueを返し、そうでない場合はfalseを返すようにします。また、指定の正しくないコマンド行オプションが見つかった場合に、validOptionsから適切なエラー・メッセージを表示することもできます。このドックレットのvalidOptionsメソッドでは、-tagオプションが1つ指定されているかどうか、そして2つ以上指定されていないかどうかをチェックしています。


Copyright © 1993, 2020, Oracle and/or its affiliates. All rights reserved.