Introducing AuthorDoclet

Posted by    |      

I'm on my way home from the Seam community meeting in Antwerp this Friday, where I managed to talk to two or three people about the Javadoc-based documentation toolset I've been working on, but there was no opportuntity to talk about it in more detail or to look at some actual examples.

The preliminary name is AuthorDoclet and I'm not attached to it - it's the first thing I entered into the project name box in IntelliJ. So I've been using AuthorDoclet to write the AuthorDoclet manual, which was a bit recursive and confusing. Especially because I'm still redesigning certain aspects of the software while I'm writing the manual.

And this is actually the most important idea behind AuthorDoclet: Stop writing anemic and synthetic unit test code. Write unit tests that people want to read, to learn your software. Write lots of quality Javadoc for your unit test classes and methods. Then press a button in AuthorDoclet and you'll get documentation automatically generated, with validated and tested examples.

This kind of approach has already been evaluated and implemented by other people, for example, there is JCite. However, the tools I've found all assume that you write documentation text in some text editor and include the code examples by putting placeholders in the text. These placeholders are then replaced with code from your Java classes by the documentation processing tool.

Validating the source code used in examples is not the only problem you'll have to deal with when you work on software documentation. The other major issue is maintaining the code while you go through many iterations of the same text, and of course many versions of the example code. If you manually copy and paste code lines from your working application into the document you are writing, you'll at some point no longer know which code needs to be updated and where, after some refactoring.

The solution offered by JCite is simple: The second time it is processing your documentation, it is going to find all the citations (included code snippets) that changed and it will show you a list of items to approve or decline.

With AuthorDoclet, you should not even have this problem because instead of referencing the code snippets from the text for inclusion, you write the text into the same file as the code, as Javadoc comments. So when the code changes, you immediately see the text that describes that code example. When you change the name of a class, method, or field, any references from your Javadoc comments (in all source files!) will be updated automatically as well. (I'm assuming that your IDE supports Javadoc refactoring.)

You still need an external master template file in AuthorDoclet which describes your documentation structure. The following example will make this easier to understand. Create an XHTML file as your master template:

<html xmlns="http://www.w3.org/1999/xhtml">
<head>
    <title>Hello World Source</title>
</head>
<body>
    <div>
        <a class="citation"
           href="example/helloworld/HelloWorld.java"/>
    </div>
</body>
</html>

When processed by AuthorDoclet, this XHTML file will be transformed into the result XHTML file, and all tags that are known to the AuthorDoclet processing pipeline (that's an implementation detail) are going to be handled. The citation anchor is going to trigger the inclusion of the source of HelloWorld.java as source within that <div>. You can organize your <div>'s into chapters and (sub-)sections.

Now, this was not an example of Javadoc inclusion, just the simpler case of Java source inclusion. This is Javadoc citation:

<html xmlns="http://www.w3.org/1999/xhtml">
<head>
    <title>Hello World Documentation</title>
</head>
<body>
    <div>
        <a class="citation"
           href="javadoc://example.helloworld.HelloWorldTest#testHello()"/>
    </div>
</body>
</html>

You'll probably recognize the syntax of this javadoc:// reference: It's the same you use in Javadoc with @link and @see tags. Your IDE can detect these strings and refactor the href value when the class or method name changes.

The Javadoc, which is also XHTML, is going to be included between the <div> element. If there are any <a class="citation"/> within that Javadoc - again, we are talking about the Javadoc of the testHello() method - they are going to be processed as well:

/**
* Testing Hello World
* <p>
* Let's assume you want to say "Hello World". The following <em>example</em> shows you how
* to do that:
* </p>
* <a class="citation" href="javacode://example.helloworld.HelloWorld#testHello()"/>
* <p>
* This was easy, right?
* </p>
*/
@Test
public void testHello() {
    System.out.println("Hello World!");
}

Note the scheme of that URI: The javacode:// prefix is enabling the dot-notation for package, class, and method names (Javadoc @see syntax). Without this scheme, you'd reference the .java file directly as shown earlier.

Processing this Javadoc comment is a recursive operation: If it would contain an anchor that cites another Javadoc comment - be it package, class, or method level - that Javadoc comment would also be transformed and so on.

AuthorDoclet currently also supports various syntaxes for inclusion/exclusion of source lines, and a few special options I'm going to show some other time.

The output document is XHTML markup, and styling, or printing this document is outside of the scope of AuthorDoclet. You can get an easy preview if you write a CSS file and open it in the browser - remember that you control the XHTML element identifiers and CSS classes directly:

<html xmlns="http://www.w3.org/1999/xhtml">
<head>
    <title>Hello World Documentation</title>
</head>
<body>
<div>
    <div class="citation javadoc" id="javadoc.example.helloworld.HelloWorldTest-testHello__">
        <div class="title">Testing Hello World</div>
        <div class="content">
            <p>
                Let's assume you want to say "Hello World". The following <em>example</em> shows you how
                to do that:
            </p>

            <div class="citation javacode" id="javacode.example.helloworld.HelloWorldTest-testHello__">
                <div class="content"><![CDATA[
                @Test
                public void testHello() {
                    System.out.println("Hello World!");
                }
                ]]></div>
            </div>
            <p>
                This was easy, right?
            </p>
        </div>
    </div>
</div>
</body>
</html>

AuthorDoclet also supports linking, e.g. you can write {@link example.helloworld.HelloWorld#testHello()} in any of your Javadoc comments, and a cross-reference (a regular link...) to the citation will be generated in the output.

Writing an XSL:FO utility that converts XHTML to nice-looking PDFs is going to be easy. I guess iText would work as well, although I've not spend any time so far on the output transformation for consumption.


Back to top