Generating AsciiDoc using a Java annotation processor
In the past I have helped a number of customers with their journey of migrating their Java 8 based applications to Java 17 (and Java 21 later on). I came up with the idea of creating a slide deck covering the major Java language and API improvements to teach my customers and give some motivation to move on to the latest Java releases.
The essential part has been a suite of examples of new and updated features of each Java release. I wanted the code to be tested with the JUnit framework and I wanted the slide deck to always be in sync with the code. This was the point where I launched the docbuilder project.
The docbuilder annotation processor is able to process a series of annotations for directing the processor to generate an AsciiDoc document. It uses information extracted from the Java code using reflection and information explicitly provided by annotation values.
With that approach it is possible to have fully functional code that is tested and is the source for automatically generated documentation.
Generating a document from a class
Let’s have a look at the following Java source file that has been annotated by docbuilder annotations.
nine/lang/TryWithResource.java
Unresolved directive in <stdin> - include::content/code/2024/java-x-enhancements/src/main/java/nine/lang/TryWithResource.java[]
The above class’s name is TryWithResource
. The @Slide
annotation directs the annotation processor to create a new AsciiDoc document named nine/lang/TryWithResource.adoc
.
It derives the section header from the class name by turning the camel cased class name into a section title.
nine/lang/TryWithResource.adoc
Unresolved directive in <stdin> - include::content/code/2024/java-x-enhancements/build/generated/sources/annotationProcessor/java/main/nine/lang/TryWithResource.adoc[]
Each method produces a titled block that includes a tagged region from the source file.
The tag is derived from the method name but can be customized by the @Snippet
annotation (e.g. @Snippet(tag = "withJava9")
).
Its title is derived from the camel cased method name but can be customized by the @Snippet
annotation (e.g. @Snippet(caption="With Java 9"
).
Custom AsciiDoc content is provided by adding @Paragraph
annotations which can be applied to any class and any method.
Generating a chapter from a package
Now we have a set of AsciiDoc files for each processed Java source file.
Using a package-info.java
file we can create a document to include all of these documents into a single document.
A package can be annotated using the @Chapter
annotation
nine/lang/package-info.java
Unresolved directive in <stdin> - include::content/code/2024/java-x-enhancements/src/main/java/nine/lang/package-info.java[]
nine/lang/package-info.adoc
Unresolved directive in <stdin> - include::content/code/2024/java-x-enhancements/build/generated/sources/annotationProcessor/java/main/nine/lang/package-info.adoc[]
Summary
The docbuilder project is currently under development.
It was started to automatically create reveal.js slide decks which is still visible from annotations like @Slide
.
The plan is to gradually convert it into a more general purpose tool for generating any kind of markup.
Currently, there is only a single implementation for producing AsciiDoc but everything is in place for plugging in other markup formats.
It already does a good job generating AsciiDoc as shown by the first post in a series of posts covering the latest additions and improvements introduced starting with the Java 9 release and onward.