Skip to content

GraphCompose v2.0.0

Choose a tag to compare

@github-actions github-actions released this 13 Jul 06:41
· 116 commits to main since this release

Note

Documentation clarification

GraphCompose v2.0.0 is the current stable, module-first release. For the drop-in PDF-capable setup, use io.github.demchaav:graph-compose:2.0.0. For a lean setup with an explicitly selected backend, use graph-compose-core.

The README.md preserved inside this immutable tag still contains an outdated status line naming v1.9.1 as the latest stable release. The tagged code, Maven coordinates, and release itself are 2.0.0.

The tag has intentionally not been modified or force-moved. For current documentation, see the main branch, the module selection guide, and the 2.0 migration guide.


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.*, and templates.proposal.*, all on BrandTheme — is now the
    single template surface.
  • The standalone BusinessTheme design-token bundle (and its DocumentPalette /
    SpacingScale / TextScale / TablePreset companions) is no longer part of the
    library. It lives on only as a styling helper inside the examples module; author
    documents with explicit DocumentColor / DocumentTextStyle values or a template
    BrandTheme.
  • The DSL name-aliases DocumentSession.builder() and DocumentDsl.text() have been
    removed. Use DocumentSession.dsl() and DocumentDsl.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. Use linkTarget() and read the external URI from
    ExternalLinkTarget.options().
  • The unused engine-internal Font.adjustFontSizeToFit(...) (and its PdfFont /
    WordFont implementations) has been removed; text auto-sizing is resolved by the
    layout compiler.
  • The dormant Entity-Component-System engine internals have been removed: the
    EntityManager / SystemECS runtime, the Entity component model with its
    geometry / coordinator / renderable companions, the ECS render pipeline
    (engine.render.* and the guide renderers under engine.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 public guideLines(...) 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 /ID from 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 via protect(...)
    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 new MultiSectionDocument.toPdfBytes(FixedLayoutRenderer) /
    writePdf(FixedLayoutRenderer, OutputStream) overloads — the multi-section
    counterpart of DocumentSession.render(backend).
  • The layered template packages dropped their .v2 suffix:
    com.demcha.compose.document.templates.<family>.v2.*
    com.demcha.compose.document.templates.<family>.* for cv, coverletter,
    invoice, and proposal. 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-core coordinate, and the original graph-compose coordinate
    becomes a thin drop-in aggregator
    that depends on graph-compose-core — so an
    existing graph-compose dependency 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 the graph-compose wrapper aggregates so a
    bare graph-compose still renders PDF, while graph-compose-core alone is lean
    (it throws MissingBackendException if asked to render without a backend). The
    built-in templates now ship in graph-compose-templates (opt-in; the
    graph-compose wrapper does not bundle them). The
    optional graph-compose-fonts / graph-compose-emoji artifacts are unchanged.
    Full install guidance ships with 2.0.0.
  • graph-compose-render-pdf is a separate artifact: the entire PDFBox backend —
    document.backend.fixed.pdf.** and the engine.render.pdf.** render tree — plus
    PDFBox, zxing (barcodes), and the commons-logging→SLF4J bridge leave
    graph-compose-core. The core keeps the DocumentSession API and the
    ServiceLoader seam (FixedLayoutBackendProvider / FontMetricsProvider); the
    PDF provider ships in render-pdf and is discovered at runtime. Depend on
    graph-compose (or graph-compose-render-pdf directly) for PDF; a bare
    graph-compose-core renders nothing until a backend is on the classpath.
  • graph-compose-templates is 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. Add graph-compose-templates for the ready-made presets; a
    consumer that used them through graph-compose before must now add this artifact
    (the com.demcha.compose.document.templates.** packages are unchanged).
  • The semantic office backends are separate artifacts and Apache POI leaves the
    engine: DocxSemanticBackend ships in graph-compose-render-docx (which brings
    POI transitively — add it to export DOCX), and PptxSemanticBackend ships in its
    own graph-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-poi build profile is retired.
  • graph-compose-testing is now a separate artifact: the consumer testing
    support — LayoutSnapshotAssertions (deterministic layout snapshots) and
    PdfVisualRegression (pixel-diff of rendered pages) — leaves the
    graph-compose jar 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; add graph-compose-testing
    at test scope to keep using them.
  • graph-compose-bundle is 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-coverage module runs JaCoCo report-aggregate over the engine, the
    PDF backend, and the built-in templates plus the graph-compose-qa cross-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 .v2 package rename, the BusinessTheme removal, the retired classic
    presets, and Font.adjustFontSizeToFit — each with its migration action.