| # Doclet Overview |

## 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 JavaTM 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 SunTM 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:

1. 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 RootDoc as a parameter.
2. Compile your doclet. You can use the compiler in the Java 2 SDK, javac.
3. 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 the `public static boolean start` method. The `start` 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 include `tools.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 run `javadoc -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 `Tag` that represent your custom tags. One of the easiest ways to do that is to use the `tags(String)` 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 `text` 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 called `optionLength(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 the `optionLength` method in our doclet must return `2` for 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 return `true` if the option usage is valid, and `false` otherwise. You can also print appropriate error messages from `validOptions` 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.

Copyright © 1995-98 Sun Microsystems, Inc. All Rights Reserved. |