Skip to content

GraphCompose 2.0

v2.0.0 Breaking

This release includes 7 breaking changes for platform teams planning a safe upgrade.

Published 14d Build & Package
✓ No known CVEs patched
Read the diff → Tool health → What is this tool? →

✓ No known CVEs patched in this version

Topics

business-documents cv-templates declarative-api document-generation invoice-template java
+12 more
java-17 layout-engine maven pagination pdf pdf-generator pdf-lib pdf-library pdfbox3 report-generation snapshot-testing template-engine

Affected surfaces

breaking_upgrade

ReleasePort's take

Moderate signal
editorial:auto 12d

GraphCompose 2.0 removes several template presets, design‑token bundles, DSL aliases, PDF overloads, linkOptions accessor, unused Font method, dormant ECS internals, and drops the `.v2` suffix from layered template packages.

Why it matters: All breaking changes have severity 70; update code to use builder(), paragraph(), backend‑neutral metadata APIs, new linkTarget API, layout compiler for font sizing, remove references to removed ECS components, and adjust import statements before migrating to v2.0.0.

Summary

AI summary

Broad release touches Packaging, Build, Public API, and Internal.

Changes in this release

Breaking High

Removed classic CV and cover-letter template presets; use layered templates.

Removed classic CV and cover-letter template presets; use layered templates.

Source: llm_adapter@2026-07-15

Confidence: high

Breaking High

Removed standalone BusinessTheme design-token bundle; use explicit DocumentColor/DocumentTextStyle.

Removed standalone BusinessTheme design-token bundle; use explicit DocumentColor/DocumentTextStyle.

Source: llm_adapter@2026-07-15

Confidence: high

Breaking High

Removed DSL name-aliases DocumentSession.builder() and DocumentDsl.text(); use builder() and paragraph().

Removed DSL name-aliases DocumentSession.builder() and DocumentDsl.text(); use builder() and paragraph().

Source: llm_adapter@2026-07-15

Confidence: high

Breaking High

Removed PDF‑typed document‑chrome overloads on DocumentSession; use backend‑neutral metadata/watermark/protect/header/footer.

Removed PDF‑typed document‑chrome overloads on DocumentSession; use backend‑neutral metadata/watermark/protect/header/footer.

Source: llm_adapter@2026-07-15

Confidence: high

Breaking High

Removed linkOptions() accessor; use linkTarget() and ExternalLinkTarget.options().

Removed linkOptions() accessor; use linkTarget() and ExternalLinkTarget.options().

Source: llm_adapter@2026-07-15

Confidence: high

Breaking High

Removed dormant ECS engine internals (EntityManager, SystemECS, Entity components, render pipeline).

Removed dormant ECS engine internals (EntityManager, SystemECS, Entity components, render pipeline).

Source: llm_adapter@2026-07-15

Confidence: high

Breaking High

Package rename: layered template packages dropped `.v2` suffix; update imports.

Package rename: layered template packages dropped `.v2` suffix; update imports.

Source: llm_adapter@2026-07-15

Confidence: high

Feature Medium

Added reproducible PDF output (`@Beta`) via PdfFixedLayoutBackend.builder().deterministic().

Added reproducible PDF output (`@Beta`) via PdfFixedLayoutBackend.builder().deterministic().

Source: llm_adapter@2026-07-15

Confidence: high

Feature Low

Multi‑section documents support reproducible PDF via MultiSectionDocument.toPdfBytes() and writePdf().

Multi‑section documents support reproducible PDF via MultiSectionDocument.toPdfBytes() and writePdf().

Source: granite4.1:30b@2026-07-15-audit

Confidence: low

Deprecation Medium

Removed unused Font.adjustFontSizeToFit(...) method; text auto‑sizing handled by layout compiler.

Removed unused Font.adjustFontSizeToFit(...) method; text auto‑sizing handled by layout compiler.

Source: llm_adapter@2026-07-15

Confidence: high

Refactor Low

Split monolithic engine into modules: graph-compose-core, graph-compose-render-pdf, graph-compose-templates, etc.

Split monolithic engine into modules: graph-compose-core, graph-compose-render-pdf, graph-compose-templates, etc.

Source: llm_adapter@2026-07-15

Confidence: high

Refactor Low

Bounded process-wide image caches with LRU eviction to prevent unbounded memory growth.

Bounded process-wide image caches with LRU eviction to prevent unbounded memory growth.

Source: granite4.1:30b@2026-07-15-audit

Confidence: low

Full changelog

[!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.

Breaking Changes

  • Removed classic (pre‑layered) CV, cover‑letter, invoice, and proposal template presets; all templates now use the layered stack on `BrandTheme`.
  • Removed standalone `BusinessTheme` design‑token bundle from the library; it remains only in example code.
  • Removed DSL name aliases `DocumentSession.builder()` and `DocumentDsl.text()`. Use `DocumentSession.dsl()` and `DocumentDsl.paragraph()`.
  • Removed PDF‑typed overloads on `DocumentSession`: `metadata(PdfMetadataOptions)`, `watermark(PdfWatermarkOptions)`, `protect(PdfProtectionOptions)`, `header(PdfHeaderFooterOptions)`, `footer(PdfHeaderFooterOptions)`. Use backend‑neutral equivalents (`metadata(DocumentMetadata)`, etc.).
  • Removed `linkOptions()` accessor on document nodes and inline runs. Use `linkTarget()` with `ExternalLinkTarget.options()`.
  • Removed internal engine utilities: `Font.adjustFontSizeToFit(...)`, the dormant ECS internals (`EntityManager`, `SystemECS`, layout pipeline, snapshot extractor).
  • Split monolithic artifact into modules; `graph-compose` now depends on `graph-compose-core` and aggregates backends/templates. Consumers must adjust dependencies (e.g., add `graph-compose-render-pdf` for PDF rendering, `graph-compose-templates` for built‑in templates).

Weekly OSS security release digest.

The CVE patches and breaking changes that affected production tools this week. One email, every Sunday.

No spam, unsubscribe anytime.

Share this release

Track GraphCompose 2.0

Get notified when new releases ship.

Sign up free

About GraphCompose 2.0

All releases →

Related context

Related tools

Beta — feedback welcome: [email protected]