Um die Ausgabe des Javadoc-tools
den eigenen Wünschen anzupassen, muß man nur eigene Doclets
schreiben. Dadurch kann man dann eigene Tags und eigene Kommandozeilenoptionen
verarbeiten, als auch andere Ausgabeformate als Html erzeugen, ohne das
man die Quelldatei ändern muß.
Um eigene Doclets zu verwenden, müssen diese (natürlich)
zuerst compiliert werden, dabei aber nicht vergessen den Classpath richtig
zu setzen (bei mir: e:\jdk1.2.2\lib\tools.jar ,die tool.jar enthält
Javadoc und die Implementierungen der Interfaces), und dann werden
sie mit -doclet an Javadoc übergeben.
javac -classpath e:\jdk1.2.2\lib\tool.jar MyDoc.java
javadoc -doclet MyDoc -classpath e:\jdk1.2.2\lib\tool.jar MyClass.java
Doclets programmieren
Doclets sind normale
Javaprogramme, die eine spezielle Doclet API benutzen, die das Erkennen
und Zerlegen des Quelltextes übernimmt und die Informationen weiterliefert.
Die Funktionen liegen im Paket sun.com.javadoc.
Doclets besitzen keine main() oder init()
Methode, sondern werden über public static boolean start(Root root)
gestartet.
Ein einfaches Beispiel für ein eigenes Doclet:
import com.sun.javadoc.*;
public class MyDoc {
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;
}
}
Dieses einfache Doclet, welches nur aus der start(RootDoc root) Methode besteht, gibt die Klassen mit denen Javadoc arbeitet auf StandardOut aus.
ein weiteres das Tags verarbeitet:
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());
}
}
}
}
}
}
Dieses Doclet sucht im Quelltext nach dem im String tagname angegebenen Tag. Die Ausgabe erfolgt auf StandardOut.
und eins für Kommandozeilenoptionen:
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;
}
}
Dies ist das vorherige Doclet erweitert um die Möglichkeit den String tagname über die Kommandozeilenfunktion -tag zu setzen.
Wie man an diesen Beispielen sieht, muß das eigene Objekt, das als Doclet dienen soll, nur die public static boolean start(RootDoc root) Methode implementieren, da diese von Javadoc aufgerufen wird. Außerdem sieht man hier, daß man kein Interfaces implementieren oder von einer bestimmten Klasse abstammen muß.
Von dem RootDoc - Objekt kann man dann die Objekte bekommen, die die Pakete, Klassen, Methoden, Parameter und Typen repräsentieren. (siehe Skizze)
Die Methoden public static int optionLength(String option) und public static boolean validOptions(String options[][], DocErrorReporter reporter) sind optional und werden implizit aufgerufen, wenn sie vorhanden sind.
Wenn man das Standardformat beibehalten will, kann man
als Ausgangspunkt das Standard-Doclet
nehmen,
indem man Unterklassen der verwandten Klassen bildet
und in diesen Methoden überschreibt und/oder hinzufügt.