AsciidoctorJ v3.0.x migration guide

AsciidoctorJ v3.0.0 introduces breaking changes. This guide will provide the steps required to update a project currently using 2.5.x version.

Update Preprocessors

In earlier versions of AsciidoctorJ (up to 2.5.x), Preprocessors were provided with a Reader object that they had to modify directly. Unlike the Ruby implementation, the Java implementation of Asciidoctor did not support Preprocessors to return a new Reader.

To address this limitation, AsciidoctorJ 3.0.0 has introduced a fix, enabling Preprocessors to create and return a new Reader. This enhancement allows Preprocessors to have more flexibility and enables a cleaner implementation.

If you have existing Preprocessors, it is essential to update the signature of their process method to return a Reader object, even if the implementation does not create a new Reader object and returns null.

The following example shows how to update a Preprocessor to return a new Reader:

Preprocessor for AsciidoctorJ 2.5.x
    public static class MyPreprocessor extends Preprocessor {

        @Override
        public void process(Document document, PreprocessorReader reader) {
            // Do something with the reader
        }
    }

To ensure compatibility with AsciidoctorJ 3.0.0, the process method of the Preprocessor needs to be modified to return a Reader. However, if you wish to maintain the same behavior as before, the method can simply return null.

Preprocessor for AsciidoctorJ 3.x.x
    public static class MyPreprocessor extends Preprocessor {

        @Override
        public Reader process(Document document, PreprocessorReader reader) {
            // Do something with the reader
            return null;
        }
    }

You may find it helpful to review the methods Processor::newReader and PreprocessorReader::read to simplify your code when creating a new Reader and reading the content of the existing Reader.

However, please note that following the steps mentioned above will be sufficient to migrate your existing processor.

Update Macro Processors

In the earlier version of AsciidoctorJ (2.5.x), the signature of Macro Processors required the implementation to return an unrestricted Object. However, the specific type that a Macro Processor had to return was unclear, making it difficult to understand the necessary implementation steps.

To address this issue, AsciidoctorJ 3.x.x has introduced the following changes:

InlineMacroProcessor::process

The implementation of this method now needs to return a PhraseNode. Please update your code accordingly to ensure that the returned value is of type PhraseNode.

BlockMacroProcessor::process

The implementation of this method now needs to return a StructuralNode. Make sure to modify your implementation to return a StructuralNode as required.

Moreover, there was a problem with the first parameter of the process method in InlineMacroProcessors. Previously, it incorrectly expected a PhraseNode as the first parameter.

To resolve this issue, AsciidoctorJ 3.x.x has rectified the first parameter of InlineMacroProcessor::process to be a StructuralNode. Please ensure that you update your code accordingly to reflect this change.

If you have any further questions or concerns, please refer to the updated documentation.

Update Inline Macro Processors

If your existing InlineMacroProcessor looks like this for AsciidoctorJ 2.5.x:

    public class TestInlineMacro extends InlineMacroProcessor {
        @Override
        public Object process(ContentNode parent, String target, Map<String, Object> attributes) {
            return createPhraseNode(parent, "quoted", "This is from an Inline Macro");
        }
    }

then you have to change it to this for AsciidoctorJ 3.x.x:

    public class TestInlineMacro extends InlineMacroProcessor {
        @Override
        public PhraseNode process(StructuralNode parent, String target, Map<String, Object> attributes) {
            return createPhraseNode(parent, "quoted", "This is from an Inline Macro");
        }
    }

In the above example you can see that the return type and the type of the first parameter of the process method have changed.

Update Block Macro Processors

If your existing BlockMacroProcessor looks like this for AsciidoctorJ 2.5.x:

    public class TestBlockMacro extends BlockMacroProcessor {
        @Override
        public Object process(StructuralNode parent, String target, Map<String, Object> attributes) {
            return createBlock(parent, "paragraph", "This is from a Block Macro");
        }
    }

then you have to change it to this for AsciidoctorJ 3.x.x:

    public class TestBlockMacro extends BlockMacroProcessor {
        @Override
        public StructuralNode process(StructuralNode parent, String target, Map<String, Object> attributes) {
            return createBlock(parent, "paragraph", "This is from a Block Macro");
        }
    }

Removal of deprecated methods in org.asciidoctor.Options

Several methods in org.asciidoctor.Options class that were marked as @Deprecated have been removed. This has been done to remove duplicated features and simplify the API interaction.

Simplification of Options initialization

In v2.5.x the following alternatives to initialize Options where possible:

Using Java Constructor and setters
Options options = new Options();
options.setBackend("html5");
options.setSafe(SafeMode.UNSAFE);
options.setMkDirs(true);
Using Map constructor
Map<String, Object> optionsMap = new HashMap<>();
optionsMap.put("backend", "html5");
optionsMap.put("sage", SafeMode.UNSAFE);
optionsMap.put("mkdirs", true);
Options options = new Options(optionsMap);
Using OptionsBuilder.options() and get() methods
Options options = OptionsBuilder.options()
    .backend("html5")
    .mkDirs(true)
    .safe(SafeMode.UNSAFE)
    .get();

The new API streamlines the process with a more standard builder approach, in which

  • Only interaction with org.asciidoctor.Options is required.

  • Nested methods offer IDE completion and creation of immutable instances.

  • Improved code readability through indentation.

From v3.0.x, use the new builder() and build() methods from org.asciidoctor.Options.

Using Options builder
Options options = Options.builder()
    .backend("html5")
    .mkDirs(true)
    .safe(SafeMode.UNSAFE)
    .build();

Note that Options setter methods are still available, that means that Options instances can still be modified as in this example.

Using setters on an instance
Options options = Options.builder().build();
options.setBackend("html5");
options.setSafe(SafeMode.UNSAFE);
options.setMkDirs(true)

Free key-value insertion is still possible using:

  • OptionsBuilder::option(String option, Object value)

  • Options::setOption(String option, Object value)

Simplification of Attributes injection in Options

The previous API offered the following ways to inject attributes to an Options instance.

Using Attributes instance setter
Attributes attributes = new Attributes();
options.setAttributes(attributes);
Using Map setter
Map<String, Object> attributesMap = new HashMap<>();
attributesMap.put("toclevels", 2);
attributesMap.put("icons", "font");
options.setAttributes(attributesMap);

Also, in v2.5.x it is possible to pass attributes to an OptionsBuilder.

Using OptionsBuilder’s Attributes instance setter
Attributes attributes = new Attributes();
Options options = OptionsBuilder.options()
    .attributes(attributes)
    .get();
Using OptionsBuilder’s Map setter
Map<String, Object> attributesMap = new HashMap<>();
attributesMap.put("toclevels", 2);
attributesMap.put("icons", "font");
Options options = OptionsBuilder.options()
    .attributes(attributesMap)
    .get();
Using OptionsBuilder’s AttributesBuilder setter
AttributesBuilder attributesBuilder = AttributesBuilder.attributes();
Options options = OptionsBuilder.options()
    .attributes(attributesBuilder)
    .get();

All these alternatives have been unified in two methods for Options and one for OptionsBuilder.

Using Attributes setter in Options
Attributes attributes = Attributes.builder()
    .icons("font")
    .build();

Options options = Options.builder().build();
options.setAttributes(attributes);
Using attributes Map setter in Options
Map<String, Object> attributesMap = new HashMap<>();
attributesMap.put("toclevels", 2);
attributesMap.put("icons", "font");

Options options = Options.builder().build();
options.setAttributes(attributesMap);
Using Attributes instance setter in OptionsBuilder
Attributes attributes = Attributes.builder()
    .icons("font")
    .build();
Options options = Options.builder()
    .attributes(attributes)
    .build();

Free key-value or string insertion is still possible using:

  • AttributesBuilder::attribute(String attributeName)

  • AttributesBuilder::attribute(String attributeName, Object attributeValue)

  • Attributes::setAttributes(String attributes)

  • Attributes::setAttributes(String…​ attributes)

Removal of deprecated methods in org.asciidoctor.Attributes

Several methods in org.asciidoctor.Attributes class that were marked as @Deprecated have been removed. This has been done to remove duplicated features and simplify the API interaction.

Simplification of Attributes initialization

In v2.5.x the following alternatives to initialize Attributes where possible:

Using Java Constructor and setters
Attributes attributes = new Attributes();
attributes.setIcons("font");
attributes.setNoFooter(true);
Using Map constructor
Map<String, Object> attributesMap = new HashMap<>();
attributesMap.put("toclevels", 2);
attributesMap.put("icons", "font");
Attributes attributes = new Attributes(attributesMap);
Using AttributesBuilder.attributes() and get() methods
Attributes attributes = AttributesBuilder.attributes()
    .icons("dont")
    .noFooter(true)
    .get();

The new API streamlines the process with a more standard builder approach, in which

  • Only interaction with org.asciidoctor.Attributes is required.

  • Nested methods offer IDE completion and creation of immutable instances.

  • Improved code readability through indentation.

From v3.0.x, use the new builder() and build() methods from org.asciidoctor.Attributes.

Using Attributes builder
Attributes attributes = Attributes.builder()
    .icons("dont")
    .noFooter(true)
    .build();

Note that Attributes setter methods are still available, that means that Attributes instances can still be modified as in this example.

Using setters on an instance
Attributes attributes = Attributes.builder().build();
attributes.setIcons("font");
attributes.setNoFooter(true);

Free key-value insertion is still possible using:

  • AttributesBuilder::attribute(String attributeName)

  • AttributesBuilder::attribute(String attributeName, Object attributeValue)

  • Attributes::setAttribute(String attributeName, Object attributeValue)

  • Attributes::setAttributes(String attributes)

  • Attributes::setAttributes(String…​ attributes)

  • Attributes::setAttributes(Map<String, Object> attributes)

Removal of asMap from OptionsBuilder and AttributesBuilder

In v2.5.x it is possible to obtain the backing Map<String,Object> for both options and attributes.

Obtaining backing Map for OptionsBuilder
Map<String, Object> optionsMap = Options.builder()
    .backend("html5")
    .mkDirs(true)
    .safe(SafeMode.UNSAFE)
    .asMap();
Obtaining backing Map for AttributesBuilder
Map<String, Object> attributesMap = Attributes.builder()
    .icons("font")
    .sectionNumbers(true)
    .asMap();

To remove feature duplication and avoid confusion between values in the actual org.asciidoctor.Attributes and org.asciidoctor.Options and their respective builders, asMap it’s no longer available in both builders.

To obtain the backing up, use the map() method from the actual org.asciidoctor.Attributes and org.asciidoctor.Options instances.

Options::map() and Attributes::map() are marked as deprecated and subject to change at some point, but are still maintained and safe to use in v3.0.x.
Obtaining backing Map for Options
Options options = Options.builder()
    .backend("html5")
    .mkDirs(true)
    .safe(SafeMode.UNSAFE)
    .build();
Map<String, Object> optionsMap = options.map();
Obtaining backing Map for Attributes
Attributes attributes = Attributes.builder()
    .icons("font")
    .sectionNumbers(true)
    .build();
Map<String, Object> attributesMap = attributes.map();

Removal of deprecated methods in org.asciidoctor.Asciidoctor

Several methods in org.asciidoctor.Asciidoctor that were marked as @Deprecated have been removed.

Removal of methods using Map<String,Object> as options input

To streamline the API, only methods using Options instances have been left in the org.asciidoctor.Asciidoctor. That means that the following methods are no longer available.

Removed convert methods
String convert(String content, Map<String, Object> options);
String convertFile(File file, Map<String, Object> options);

void convert(Reader contentReader, Writer rendererWriter, Map<String, Object> options) throws IOException;

<T> T convert(String content, Map<String, Object> options, Class<T> expectedResult);
<T> T convertFile(File file, Map<String, Object> options, Class<T> expectedResult);

String[] convertDirectory(Iterable<File> directoryWalker, Map<String, Object> options);
String[] convertFiles(Collection<File> files, Map<String, Object> options);
Removed load methods
Document load(String content, Map<String, Object> options);
Document loadFile(File file, Map<String, Object> options);

For each of the methods above there’s an equivalent using org.asciidoctor.Options. Use those when migrating to v3.0.0.

Removal of methods using OptionsBuilder as options input

Likewise to the methods seen in the previous section, the following methods are also no longer available.

Removed convert methods
String convert(String content, OptionsBuilder options);
String convertFile(File file, OptionsBuilder options);

void convert(Reader contentReader, Writer rendererWriter, OptionsBuilder options) throws IOException;

<T> T convert(String content, OptionsBuilder options, Class<T> expectedResult);
<T> T convertFile(File file, OptionsBuilder options, Class<T> expectedResult);

String[] convertDirectory(Iterable<File> directoryWalker, OptionsBuilder options);
String[] convertFiles(Collection<File> files, OptionsBuilder options);

For each of the methods above there’s an equivalent using org.asciidoctor.Options. Use those when migrating to v3.0.0.

Removal of methods readDocumentHeader

All implementations of Asciidoctor::readDocumentHeader have been removed because the same feature can be obtained using load with the parse_header_only option.

Using load to obtain Document header
Options options = Options.builder().option("parse_header_only", true).build();
Document document = asciidoctor.loadFile(documentHeaders, options);

List<Author> authors = document.getAuthors();
RevisionInfo revisionInfo = document.getRevisionInfo();
String doctitle = document.getDoctitle();
Title structuredDoctitle = document.getStructuredDoctitle();

As a consequence, class org.asciidoctor.ast.DocumentHeader has been also removed.

Removal of deprecated methods in org.asciidoctor.ast.Document

Several methods in org.asciidoctor.ast.Document that were marked as @Deprecated have been removed.

For each of the removed methods, the equivalent can be found below.

Removed deprecated methods
String doctitle()
boolean basebackend(String backend)
Final methods
String getDoctitle()
boolean isBasebackend(String backend)

Removal of deprecated constants from org.asciidoctor.extension.BlockProcessor

All constants in org.asciidoctor.extension.BlockProcessor class that were marked as @Deprecated have been removed.

You can find the new values in org.asciidoctor.extension.Contexts interface. See the table below for the equivalencies.

Deprecated value Contexts value

CONTEXTS

KEY

CONTEXT_OPEN

OPEN

CONTEXT_EXAMPLE

EXAMPLE

CONTEXT_SIDEBAR

SIDEBAR

CONTEXT_LITERAL

LITERAL

CONTEXT_LISTING

LISTING

CONTEXT_QUOTE

QUOTE

CONTEXT_PASS

PASS

CONTEXT_PARAGRAPH

PARAGRAPH

Removal of deprecated methods in org.asciidoctor.extension package

Several methods under org.asciidoctor.extension that were marked as @Deprecated have been removed. The new methods align better with Java naming patterns and are easily identifiable.

Removed deprecated methods
PreprocessorReader::push_include
Reader::getLineno
Reader::lines
Final methods
PreprocessorReader::pushInclude
Reader::getLineNumber
Reader::getLines

Removal of deprecated methods in org.asciidoctor.ast package

Several methods under org.asciidoctor.ast that were marked as @Deprecated have been removed. The new methods align better with Java naming patterns and are easily identifiable.

Here follows the list of affected interfaces, describing for each one the removed methods and the substitutions.

Block

Removed deprecated methods
List<String> lines()
String source()
Final methods
List<String> getLines()
String getSource()

DescriptionList, PhraseNode and List

Removed deprecated method
String render()
Final method
String convert()

ContentNode

Removed deprecated methods
String id()
ContentNode parent()
String context()
Document document()
String role()

Object getAttr(Object name, Object defaultValue, boolean inherit)
Object getAttr(Object name, Object defaultValue)
Object getAttr(Object name)

boolean hasAttr(Object name)
boolean hasAttr(Object name, boolean inherited)

boolean isAttr(Object name, Object expected)
boolean isAttr(Object name, Object expected, boolean inherit)

boolean setAttr(Object name, Object value, boolean overwrite)
Final methods
String getId()
ContentNode getParent()
String getContext()
Document getDocument()
String getRole()

Object getAttribute(Object name, Object defaultValue, boolean inherit)
Object getAttribute(Object name, Object defaultValue)
Object getAttribute(Object name)

boolean hasAttribute(Object name)
boolean hasAttribute(Object name, boolean inherited)

boolean isAttribute(Object name, Object expected)
boolean isAttribute(Object name, Object expected, boolean inherit)

boolean setAttribute(Object name, Object value, boolean overwrite)

Section

On top of the methods replaced by Java getters, both number and getNumber are replaced by getNumeral. This is done to support non-number numerals.

Removed deprecated methods
int index()
int number()
int getNumber()

String sectname()
boolean special()

boolean numbered()
Final methods
int getIndex()
String getNumeral()

String getSectionName()
boolean isSpecial()

boolean isNumbered()

StructuralNode

Removed deprecated methods
Object content()
String style()
String title()
List<StructuralNode> blocks()
Final methods
Object getContent()
String getStyle()
String getTitle()
List<StructuralNode> getBlocks()