Skip to main content
  1. Writing/

Building Java API Docs With DocFX

·926 words

For some time, at docs.microsoft.com, we’ve been using a non-standard way to document Java APIs. For example, if you take a look at this page, you will notice that it’s a regular API document. Behind the scenes, it was built with the help of Doxygen (generates structured docs from Java code), code2yaml (transforms Doxygen output into YAML) and DocFX (transforms YAML into static HTML).

As we started documenting more APIs from across the company, we’ve encountered an interesting problem - Doxygen, while a versatile tool, relies on a set of conventions that are very much specific to its own stack and are less common in the Java developer community. In particular, it would hardly support some very important Javadoc constructs, such as those pertaining to code examples.

This is when we decided that we need to overhaul the pipeline a bit - in consultation with Microsoft Cloud Developer Advocate Bruno Borges and Azure SDK engineer Jonathan Giles, we’ve determined that the best way to do this would be through a doclet. At a fundamental level, we would essentially be plugging into the standard Javadoc tooling instead of trying to abide to a less common standard. In collaboration with our engineering teams, we’ve built a DocFX doclet, that would produce the structured content that DocFX can ingest while consuming the output produced by standard Java documentation tooling.

In this post, I will describe how you can generate beautiful Java API documentation with a Javadoc-based extension.

Building the doclet #

First, clone the repository with the doclet locally. Once you have a copy, make sure that you have the Java Development Kit installed on your machine. The installation process might be different, depending on your platform. And of course, once you have Java installed, you also need to install Apache Maven - this is what we use to build the project. For macOS, this is as simple as:

brew install maven

Thank you our lord and savior Homebrew for making the installation process a breeze here. Now we are ready to build. Set the context of your terminal to the folder where you cloned the repo, and run:

mvn compile

Running mvn compile in the terminal

When the build completes, we need to make sure that we generate a JAR file. Maven can help us here too:

mvn package

Running mvn package in the terminal

We are ready to use the doclet - the JAR is now located in the targets folder, within the location where you cloned the repository.

Building documentation #

For a demo, let’s use the Azure Functions Java library, available on GitHub. Clone the repository locally, and once the process completes, execute the following javadoc call in the terminal:

javadoc \
    -encoding UTF-8 \
    -docletpath /some/path/docfx-doclet/target/docfx-doclet-1.0-SNAPSHOT-jar-with-dependencies.jar \
    -doclet com.microsoft.doclet.DocFxDoclet \
    -sourcepath /some/path/azure-functions-java-library/src/main/java \
    -outputpath /some/path/yml-test \
    -subpackages com.microsoft.azure.functions \

What this will do is generate the YAML files that DocFX needs via standard Javadoc tooling. Here is a breakdown of parameters used:

Parameter Description
-encoding Encoding for the generated documentation.
-docletpath Path to the doclet that we built with Maven earlier in the post.
-doclet The ID of the doclet being used. This should be a constant com.microsoft.doclet.DocFxDoclet.
-sourcepath The path to the source code where the package that needs to be documented is located.
-outputpath The path where the generated YAML files should be placed.
-subpackages The list of subpackages that need to be documented, separated by a colon (:).

There are two optional parameters that you can specify:

Parameter Description
-excludepackages List of excluded packages, separated by a colon (:). For example: com\.msdn\..*:com\.ms\.news\..*.
-excludeclasses List of classes that need to be excluded, separated by a colon (:). For example: .*SomeClass:com\.ms\..*AnyClass.

Generate YAML docs with Javadoc

We’re all ready to start experimenting with the generated documentation within DocFX!

Publishing the documentation #

Having the YAML files is half of the process - we now need to convert them to static HTML and see what those look like within the DocFX chrome. To do that, first we need to make sure that we download DocFX locally - you can do that from the official GitHub repository. Just grab docfx.zip and extract it locally. Within the extracted folder, you should see the DocFX executable - docfx.exe.

Now you might be wondering - if you are on Linux or macOS, *.exe is not quite the file extension you are used to seeing for executables. To mitigate this, you will need to install the Mono runtime. I would recommend installing the package from the official site instead of relying on the Homebrew distribution.

With the Mono runtime installed, we can now initialize a new DocFX documentation set - just run the following command in the terminal:

mono /path/to/docfx.exe init

Set up DocFX docset

Alternatively, if you would like to run this quickly (with no custom settings), you can run the command with the -q argument. On command success, you will have a new documentation set provisioned in the directory, to which the context was set in the terminal. Move all the previously-generated *.yml files into the docfx_project/api directory in the documentation set.

To build the content, set the context of the terminal inside the docfx_project folder, and run:

mono /path/to/docfx.exe

Generate HTML for the YAML files in DocFX

Last step is us actually serving the generated files on a local server. To do that, run:

mono /path/to/docfx.exe serve _site

Here, _site is the name of the folder where the generated HTML files were placed. In the terminal, DocFX will tell you the URL where you can access the served site (it’s usually https://localhost:8080).

Running site in Safari

That’s it! You now have Java API documentation inside DocFX, with no content loss, and preserving the structure of your familiar Javadoc comments!