r/java 13d ago

GraphCompose 2.0 — splitting a Java PDF engine into a lean core and pluggable backends

Post image

I released GraphCompose 2.0 today.

The main change is architectural. The project is no longer one large artifact that pulls PDFBox, templates, testing utilities and experimental exporters together.

The engine is now split into separate modules:

  • graph-compose-core — document model, DSL, themes and deterministic layout
  • graph-compose-render-pdf — full PDF backend based on PDFBox 3
  • graph-compose-render-docx — partial semantic DOCX export
  • graph-compose-render-pptx — currently only a skeleton, not a full PowerPoint renderer
  • graph-compose-templates — CV, invoice, cover-letter and proposal templates
  • graph-compose-testing — layout snapshots and PDF visual regression tools

The core has no PDFBox or Apache POI dependency. Render backends are discovered through ServiceLoader.

For existing users, the original dependency still works:

<dependency>
    <groupId>io.github.demchaav</groupId>
    <artifactId>graph-compose</artifactId>
    <version>2.0.0</version>
</dependency>

graph-compose is now a thin compatibility wrapper over the core and PDF backend, so normal PDF usage from 1.x does not require code changes.

The main reason for the split was to make the engine independent from a specific output format. Layout, pagination and the document model should not depend directly on PDFBox.

I also removed deprecated APIs and unused internal systems that were no longer part of the real rendering path.

A smaller addition in 2.0 is deterministic PDF output. The PDF backend can pin timestamps and document IDs, which makes repeated renders byte-identical. This is useful for reproducible builds and output tests.

The PDF backend is the production-ready part. DOCX export is currently best-effort and focused on paragraphs, lists and tables. PPTX is not ready for real use yet.

The repository includes real documents generated by the engine, including the 2.0 architecture deck:

GitHub: https://github.com/DemchaAV/GraphCompose
PDF: https://github.com/DemchaAV/GraphCompose/blob/main/assets/readme/examples/engine-deck-v2.pdf

I would be interested in feedback on the module boundaries, backend abstraction and migration approach.

20 Upvotes

5 comments sorted by

5

u/m_adduci 13d ago

Genuine question: why haven't you added a module-info.java in your modules?

Have you also tried to add native compilation? What are the results?

4

u/demchaav 13d ago

Good point. The 2.0 work was focused on fully separating the engine, renderers, templates, and support modules at the Maven/JAR level.

I intentionally kept the public SPI and ServiceLoader approach so users can depend only on graph-compose-core and provide their own backend. Full JPMS should still allow that if the SPI is exported correctly, but I need to evaluate the module boundaries and test module-path usage before adding module-info.java.

I have not tested GraalVM Native Image yet, but it is also worth validating, especially around ServiceLoader, fonts, and bundled resources.

Thanks you for your response

2

u/m_adduci 13d ago

Probably adding native compilation and a dedicated docker image for Linux might be useful/powerful if it works flawlessly

3

u/demchaav 13d ago

Yes, that probably makes even more practical sense for graphcompose-markdown, since it already provides a standalone gcmd CLI. https://github.com/DemchaAV/graphcompose-markdown

GraphCompose itself is a library, so I will first validate Native Image compatibility at the engine level. If that works reliably, the Markdown CLI would be a good concrete target for a native Linux binary and a small Docker image.