v2.0.0 — 2026-07-13
The 2.0 development line. Binary-breaking by design — japicmp runs report-only
for this cycle.
Removed
- The classic (pre-layered) CV and cover-letter template presets have been removed.
The layered template stack —templates.cv.*,templates.coverletter.*,
templates.invoice.*, andtemplates.proposal.*, all onBrandTheme— is now the
single template surface. - The standalone
BusinessThemedesign-token bundle (and itsDocumentPalette/
SpacingScale/TextScale/TablePresetcompanions) is no longer part of the
library. It lives on only as a styling helper inside the examples module; author
documents with explicitDocumentColor/DocumentTextStylevalues or a template
BrandTheme. - The DSL name-aliases
DocumentSession.builder()andDocumentDsl.text()have been
removed. UseDocumentSession.dsl()andDocumentDsl.paragraph(). - The PDF-typed document-chrome overloads on
DocumentSession—
metadata(PdfMetadataOptions),watermark(PdfWatermarkOptions),
protect(PdfProtectionOptions),header(PdfHeaderFooterOptions)and
footer(PdfHeaderFooterOptions)— have been removed in favour of the canonical,
backend-neutral overloads (metadata(DocumentMetadata),watermark(DocumentWatermark),
protect(DocumentProtection),header(DocumentHeaderFooter),
footer(DocumentHeaderFooter)). The PDF option types remain available on
PdfFixedLayoutBackend.builder()for advanced backend-level configuration. - The
linkOptions()accessor on the document nodes and inline runs (paragraph, table,
image, shape, ellipse, line, barcode, and the inline image / shape / text runs) has
been removed. UselinkTarget()and read the external URI from
ExternalLinkTarget.options(). - The unused engine-internal
Font.adjustFontSizeToFit(...)(and itsPdfFont/
WordFontimplementations) has been removed; text auto-sizing is resolved by the
layout compiler. - The dormant Entity-Component-System engine internals have been removed: the
EntityManager/SystemECSruntime, theEntitycomponent model with its
geometry / coordinator / renderable companions, the ECS render pipeline
(engine.render.*and the guide renderers underengine.render.guides), and
LayoutSnapshotExtractor. None were reachable from the live render path —
DocumentSession→ layout compiler → fixed-layout backend — so document layout,
PDF output, and the publicguideLines(...)overlay are unchanged.
Public API
- Reproducible PDF output (
@Beta).PdfFixedLayoutBackend.builder().deterministic(true)
(or.deterministic(Instant)for an explicit timestamp) pins the document
CreationDate / ModDate and derives the PDF/IDfrom the document metadata instead
of PDFBox's time-seeded default, so the same document renders to byte-identical PDF
bytes across runs — for reproducible builds and byte-level output tests. Off by
default (output keeps the live timestamp and/ID). PDF encryption viaprotect(...)
can reintroduce randomness (AES-256 uses random salts), so an encrypted document is
not byte-reproducible even with this enabled. Multi-section documents opt in through
the newMultiSectionDocument.toPdfBytes(FixedLayoutRenderer)/
writePdf(FixedLayoutRenderer, OutputStream)overloads — the multi-section
counterpart ofDocumentSession.render(backend). - The layered template packages dropped their
.v2suffix:
com.demcha.compose.document.templates.<family>.v2.*→
com.demcha.compose.document.templates.<family>.*forcv,coverletter,
invoice, andproposal. Update imports accordingly — behaviour and rendering are
unchanged; this is a package rename only.
Packaging
- 2.0 splits the monolithic engine into modules. The engine now builds under a new
graph-compose-corecoordinate, and the originalgraph-composecoordinate
becomes a thin drop-in aggregator that depends ongraph-compose-core— so an
existinggraph-composedependency keeps compiling and rendering PDF unchanged.
Consumer-testing support (graph-compose-testing) and the semantic DOCX / PPTX
backends (graph-compose-render-docx/graph-compose-render-pptx) are already
separate artifacts; the PDF render backend now lives in
graph-compose-render-pdf, which thegraph-composewrapper aggregates so a
baregraph-composestill renders PDF, whilegraph-compose-corealone is lean
(it throwsMissingBackendExceptionif asked to render without a backend). The
built-in templates now ship ingraph-compose-templates(opt-in; the
graph-composewrapper does not bundle them). The
optionalgraph-compose-fonts/graph-compose-emojiartifacts are unchanged.
Full install guidance ships with 2.0.0. graph-compose-render-pdfis a separate artifact: the entire PDFBox backend —
document.backend.fixed.pdf.**and theengine.render.pdf.**render tree — plus
PDFBox, zxing (barcodes), and the commons-logging→SLF4J bridge leave
graph-compose-core. The core keeps theDocumentSessionAPI and the
ServiceLoaderseam (FixedLayoutBackendProvider/FontMetricsProvider); the
PDF provider ships in render-pdf and is discovered at runtime. Depend on
graph-compose(orgraph-compose-render-pdfdirectly) for PDF; a bare
graph-compose-corerenders nothing until a backend is on the classpath.graph-compose-templatesis a separate artifact: the built-in CV, cover-letter,
invoice, and proposal templates (document.templates.**) leave the engine. They
are pure authoring code over the canonical DSL, so the module depends only on
graph-compose-core. Addgraph-compose-templatesfor the ready-made presets; a
consumer that used them throughgraph-composebefore must now add this artifact
(thecom.demcha.compose.document.templates.**packages are unchanged).- The semantic office backends are separate artifacts and Apache POI leaves the
engine:DocxSemanticBackendships ingraph-compose-render-docx(which brings
POI transitively — add it to export DOCX), andPptxSemanticBackendships in its
owngraph-compose-render-pptx(a POI-free skeleton for now — add it for the
slide-safe semantic manifest). Their packages —
com.demcha.compose.document.backend.semantic.{docx,pptx}— are unchanged. The
no-poibuild profile is retired. graph-compose-testingis now a separate artifact: the consumer testing
support —LayoutSnapshotAssertions(deterministic layout snapshots) and
PdfVisualRegression(pixel-diff of rendered pages) — leaves the
graph-composejar together with its Jackson and PDFBox dependencies. The
com.demcha.compose.testing.layout/com.demcha.compose.testing.visual
packages are unchanged, so imports stay the same; addgraph-compose-testing
at test scope to keep using them.graph-compose-bundleis the batteries-included aggregate for the split layout:
one dependency pulls the default PDF stack (graph-compose= core + render-pdf),
the built-in templates (graph-compose-templates), the bundled Google fonts, and
the colour-emoji set at compatible pinned versions. The office backends
(graph-compose-render-docx/graph-compose-render-pptx) stay opt-in and are not
bundled.
Internal
- The process-wide image caches (decoded source bytes and image metadata) are now
bounded with LRU eviction instead of growing without limit. A long-lived JVM that
renders many distinct images — a rendering service, a batch job — no longer
accumulates image data indefinitely. Single documents are unaffected: the caps sit
far above any realistic distinct-image count, so a render never evicts or re-decodes.
Build
- Added report-only cross-module code coverage. A new non-published
graph-compose-coveragemodule runs JaCoCoreport-aggregateover the engine, the
PDF backend, and the built-in templates plus thegraph-compose-qacross-module
suites, so each module's coverage counts the tests that actually exercise it (a
single-module report undercounts, because much of the production code is driven from
qa at test scope). CI publishes the HTML/XML report as an artifact; no coverage
threshold is enforced yet.
Documentation
- Documented that text is laid out left-to-right only: bidirectional (RTL) reordering
and complex-script shaping (Arabic joining, Indic reordering) are not performed. Added
to the README support matrix. - The 2.0 module migration guide now lists the API changes it previously delegated to the
changelog — the.v2package rename, theBusinessThemeremoval, the retired classic
presets, andFont.adjustFontSizeToFit— each with its migration action.