Doclet Overview (original) (raw)
Contents
- The Basics
- A Simple Example Doclet
- Example - Subclassing the standard doclet
- Example - Creating and handling custom tags
- Example - Using custom command-line options
The Basics
Doclets are programs written in the Java™ programming language that use the doclet API to specify the content and format of the output of the Javadoc tool. By default, the Javadoc tool uses the "standard" doclet provided by Sun™ to generate API documentation in HTML form. However, you can supply your own doclets to customize the output of Javadoc as you like. You can write the doclets from scratch using the doclet API, or you can start with the standard doclet and modify it to suit your needs.
Here are the basic steps you need to follow to create and use your own doclet:
- Write the Java program that constitutes your doclet. Your program should import com.sun.javadoc.* in order to use the doclet API. The entry point of your program is a class with a public static boolean start method that takes a RootDocas a parameter.
- Compile your doclet. You can use the compiler in the Java 2 SDK, javac.
- Run the javadoc tool using the -doclet startingclass option to produce the output specified by your doclet, where startingclass is the fully-qualified name of the starting class mentioned in step 1 above.
The doclet API class files are in the
lib/tools.jar
file in the SDK. When you compile a doclet, the
tools.jar
must be on the class path. You can use the
-classpath
option on javac for this purpose.
If you run javadoc without the -doclet command-line option, it will default to the standard doclet to produce HTML-format API documentation.
Package com.sun.javadoc consists of interfaces that define the doclet API. The lib/tools.jar file in the Java 2 SDK contains these interfaces and also a private package with classes that implement the interfaces. The tools.jar file also contains the classes implementing the standard doclet.
A Simple Example Doclet
You can get a feeling for the way doclets work by looking at this simple example doclet that consists of one short class:
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; } }
As you might be able to guess by looking at the code, this doclet takes the classes upon which Javadoc is operating and prints their names to standard out.
This first thing to notice about the doclet is that it imports the com.sun.javadoc package in order to use the doclet APIs. As with all doclets, the entry point is thepublic static boolean start method. Thestart method takes a RootDoc as a parameter. This parameter carries information about any options specified on the command line when javadoc is run, and also about the classes and packages upon which javadoc is operating.
RootDoc defines a classes method that returns a ClassDoc array whose elements represent the classes that Javadoc parses. The for loop then prints out the names of each class in the array. (Passing a ClassDoc to println results in the printing of the name of the class that the ClassDoc represents.)
To run this doclet, you first have to compile it. You can compile it with the javac compiler. The doclet API classfiles are in the file lib/tools.jar in the Java 2 SDK which javac does not automatically load. You therefore need to includetools.jar on the compiler's classpath, as in this example:
javac -classpath C:\jdk1.3\lib\tools.jar ListClass.java
To run the ListClass doclet, you point to the compiled doclet with Javadoc's
-doclet
and
-docletpath
tags. For example, to run the doclet on a file called
MyClass.java
, you could use this command, assuming
ListClass.class
is in the current directory:
% javadoc -doclet ListClass -docletpath . MyClass.java
The output will be the string "
MyClass
". Note that this command does not require
tools.jar
to be on the class path, as the Javdoc tool automatically loads it.
A note about command-line options: If you runjavadoc -help, you'll see that the Javadoc tool has two sets of command-line options. One set is generic and will work with any doclet. The second set of options is special to the standard doclet. Options in this second set will not be available when using custom doclets. Your custom doclets can also define their own command-line options. See the example below.
To generate API documentation, a doclet will have to be considerably more complex than this simple example. If you want to customize the format of the API documentation generated by Javadoc, you may want to start with the default standard doclet and modify it as necessary rather than write your own doclet from scratch.
Example - Subclassing the Standard Doclet
To customize the output of the Javadoc tool, you need to write your own doclet that specifies the content and format of the output that you desire. If you want HTML output with roughly the same format as the default output, you can use the standard doclet as a starting point for creating your doclet. You can subclass appropriate classes in the standard doclet and then add or override methods as necessary to produce the output you want. Or you can copy the whole standard doclet and modify it. If you use a copy of the standard doclet as your starting point, you may want to remove the
package
statements at the beginning of each source file and replace them with the name of your own, new package.
For an example, see How can I modify the standard doclet to produce links to source code from the API documentation?
Example - Creating and handling custom tags
Suppose, for example, that you want use a custom tag, say
@mytag
, in your documentation comments in addition to the standard tags like
@param
and
@return
. To make use of the information in your custom tags, you need to have your doclet use instances of
that represent your custom tags. One of the easiest ways to do that is to use the
method of
Doc
or one of
Doc
's subclasses. This method returns an array of
Tag
objects representing any tags whose name matches the string argument. For example, if
method
is an instance of
MethodDoc
, then
method.tags("mytag")
would return an array of
Tag
objects representing any
@mytag
tags in the method's documentation comment. You can then access the information in your
@mytag
tags with
Tag
's
method. That method returns a string representing the content of the tag which you can parse or use as needed. For example, if a documentation comment contained one of your custom tags like this:
@mytag Some dummy text.
then the
text
method would return the string
"Some dummy text."
.
Here's a standalone doclet (not a subclass of the standard doclet) that uses these ideas to print out the text associated with all instances of a specified tag that it finds in method comments. It could be extended to find all instances of that tag in all comments.
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());
}
}
}
}
}
}
The tag for which this doclet searches is specified by the variable
tagName
. The value of the
tagName
string can be any tag name, custom or standard. This doclet writes to standard out, but its output format could be modified, for example, to write HTML output to a file.
Example - Using custom command-line options
You can write doclets that accept custom command-line options. To see how that works, let's augment the example doclet above so that it allows you to use a command-line option to specify the tag name to search for.
Any doclet that uses custom options must have a method calledoptionLength(String option) that returns an int. For each custom option that you want your doclet to recognize,optionLength must return the number of separate pieces or tokens in the option. For our example, we want to be able to use the custom option of the form -tag mytag. This option has two pieces, the -tag option itself and its value, so theoptionLength method in our doclet must return 2for the -tag option. The optionsLength method should return 0 for unrecognized options.
Here's the full, augmented doclet:
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;
}
}
In this modified doclet, the variable
tagName
is set with the command-line option
-tag
. It has a
optionLength
method returns two for our custom option. Note that an explicit call to
optionLength
isn't required.
This doclet also adds the readOptions methods that actually parses the command-line options looking for the-tag option. It makes use of the fact that the Rootdoc.options method returns a two-dimensional String array containing option information. For example, given the command
javadoc -foo this that -bar other ...
the
RootDoc.options
method will return
options()[0][0] = "-foo" options()[0][1] = "this" options()[0][2] = "that" options()[1][0] = "-bar" options()[1][1] = "other"
The number of elements in the array's second index is determined by the
optionLength
method. In this example,
optionLength
returns
3
for option
-foo
and returns
2
for option
-bar
.
The validOptions method is an optional method that you can use to test the validity of the usage of command-line tags. If the validOptions method is present, it is automatically invoked; you don't have to explicitly call it. It should returntrue if the option usage is valid, and falseotherwise. You can also print appropriate error messages fromvalidOptions when improper usages of command-line options are found. The validOptions method in this example doclet checks that the -tag option is used once and only once.