Preprocessors allow to process the raw asciidoctor sources before Asciidoctor parses and converts them. A preprocessor could for example make comments visible that should be rendered in drafts.

Our example preprocessor does exactly that and will render the comment in the following document as a note.

Normal content.

RP: This is a comment and should only appear in draft documents

The preprocessor will render the document as if it looked like this:

Normal content.

RP: This is a comment and should only appear in draft documents

The implementation of the preprocessor simply gets the AST node for the document to be created as well as a PreprocessorReader. A PreprocessorReader gives access to the raw input, on a per-line basis, allowing to fetch and manipulate content. And this is exactly what our Preprocessor does: it fetches the raw content, modifies it and stores it back so that Asciidoctor will only see our modified content.

A Preprocessor that renders comments as notes
import org.asciidoctor.ast.Document;
import org.asciidoctor.extension.Preprocessor;
import org.asciidoctor.extension.PreprocessorReader;

import java.util.ArrayList;
import java.util.List;

public class CommentPreprocessor extends Preprocessor {   (1)

    public void process(Document document, PreprocessorReader reader) {

        List<String> lines = reader.readLines();          (2)
        List<String> newLines = new ArrayList<String>();

        boolean inComment = false;

        for (String line: lines) {                        (3)
            if (line.trim().equals("////")) {
                if (!inComment) {
                inComment = !inComment;
            } else {

        reader.restoreLines(newLines);                    (4)
1 All Preprocessors must extend the class org.asciidoctor.extension.Preprocessor and implement the method process().
2 The implementation gets the whole Asciidoctor source as an array of Strings where each entry corresponds to one line.
3 Every odd occurrence of a comment start is replaced by opening an admonition block, every even occurrence is closing it. The new content is collected in a new list.
4 The processed content is restored to the original PreprocessorReader so that it replaces the content that was already consumed at the beginning of the method.

There may be multiple Preprocessors registered and every Preprocessor will be called. The order in which the Preprocessors are called is undefined so that all Preprocessors should be independent of each other.