Skip to content

Streaming xlsx reports#5480

Open
KremnevDmitry wants to merge 5 commits into
masterfrom
feature/5417-streaming-xlsx-reports
Open

Streaming xlsx reports#5480
KremnevDmitry wants to merge 5 commits into
masterfrom
feature/5417-streaming-xlsx-reports

Conversation

@KremnevDmitry

@KremnevDmitry KremnevDmitry commented Jul 16, 2026

Copy link
Copy Markdown
Contributor

Summary

Added streaming XLSX report generation for large datasets: a report band can be marked to render row-by-row straight from a database cursor, so memory stays bounded regardless of row count (verified at ~1M rows). The feature is opt-in per band and inert for existing reports.

What was done

  • Introduced a per-band streaming flag (BandDefinition, exposed via ReportBand/ReportQuery) and a Streaming checkbox in the report editor, gated to a first-level band backed by a single SQL or JPQL dataset.
  • Added a streaming XLSX formatter built on POI SXSSF that writes rows incrementally, plus supporting pieces (band feed, style cache, XLSX→CSV streaming writer, template-band model). The streaming formatter is selected automatically when a band has the flag set.
  • Added forward-only DB-cursor streaming for the SQL and JPQL loaders (configurable JDBC fetch size, read-only transaction, periodic persistence-context clearing) behind a StreamingReportDataLoader abstraction.
  • Added StreamingReportValidator that enforces the structural rules streaming requires (single dataset, first-level band, supported dataset type) and surfaces clear errors otherwise.
  • Added configuration under jmix.reports.streaming.* (fetch size and related knobs, validated to be positive) and translations (default + ru) for the new UI.
  • (jmix-premium) Added a spreadsheet-report preview size gate: results above a configurable threshold are downloaded instead of being loaded into the in-memory Vaadin Spreadsheet, avoiding RecordFormatException/OOM on huge outputs.

How it works

When a first-level band is marked streaming, the engine reads its rows from a forward-only database cursor and writes them directly into an SXSSF sheet one row at a time, so peak memory does not grow with the result size. Non-streaming bands and templates render through the existing engine unchanged. Formulas are resolved at write time — in-row formulas shift per band instance, and trailing aggregates placed below the data grow to cover all rendered rows. The render runs in a read-only transaction, and the persistence context is cleared periodically to bound managed-entity growth while lazy attributes stay resolvable through the open session. Output can be post-converted to CSV via a streaming writer.

How to use

In the report editor, check Streaming on a first-level band whose dataset is a single SQL or JPQL query (the checkbox is disabled for other configurations). Run the report with an XLSX or CSV template as usual — the streaming engine is chosen automatically. Adjust jmix.reports.streaming.fetch-size and related properties if the default cursor page size doesn't suit the data store.

Compatibility

Opt-in and backward compatible: bands are non-streaming by default, and any report that doesn't set the flag renders exactly as before.

@KremnevDmitry KremnevDmitry self-assigned this Jul 16, 2026
@KremnevDmitry KremnevDmitry linked an issue Jul 16, 2026 that may be closed by this pull request
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Streaming XLSX reports

1 participant