PDFPipe

Migrating from JasperReports / A report designer or markup toolchain

Migrating off JasperReports, and what happens to the bands

A reporting engine whose layouts are XML files built in a visual designer, organised into bands that repeat by rule, where nothing about the layout is portable and the band model has no equivalent.

What ports and what does not

The queries and the data. The report files do not. A report is an XML document describing bands, title, page header, column header, detail, group header and footer, summary, each with its own repetition rule, and the engine walks the data filling them. That model does not exist in CSS. The detail band becomes a table row, the page header becomes a running header, group bands become headings with break rules, and the summary becomes a block at the end. Each of those is a sensible translation and none of them is mechanical.

What the call becomes

JasperFillManager and JasperExportManager become a POST to /v1/pdf with html. The parameters map becomes the data you interpolate into a template. The datasource becomes the query you already have. What has no counterpart is everything the engine did beyond layout: subreports, the expression language in the report file, and the built-in variables for counts, sums and running totals. Those calculations move into your code, where they are usually easier to test.

Side by side

The old shape and the new one, with the parts that have no counterpart called out in comments rather than quietly omitted.

java
// Before
JasperPrint print = JasperFillManager.fillReport(
    "invoice.jasper", params, new JRBeanCollectionDataSource(rows));
byte[] pdf = JasperExportManager.exportReportToPdf(print);

// After: the query stays, the layout is rebuilt.
String html = templateEngine.process("invoice", context(rows, totals));

/* The band model, translated:
     title band          -> a block before the table, break-after if it
                            should have its own page
     page header band    -> options.header_html, or an @page margin box
     column header band  -> thead, which repeats on every page
     detail band         -> tbody rows
     group header band   -> a heading row, with break-after: avoid
     group footer band   -> a subtotal row
     summary band        -> a block after the table
     page footer band    -> options.footer_html

   With no counterpart:
     subreports          -> compose the markup yourself
     the expression      -> your own code; the built-in variables for
       language             counts, sums and running totals become
                            values you compute and pass in            */

The CSS delta, in both directions

What the old engine accepted that a current one does not, and what it refused that a current one wants. The second direction is the one people forget, and it is where the value of the migration is.

  • Nothing to migrate. The report file's styles are the specification for the CSS, and the designer's property panel maps onto font, size, alignment and border in a way that is tedious but unambiguous.
  • Band repetition becomes a mix of thead for the repeating header, CSS break rules for the group behaviour, and the header and footer options for page furniture.
  • The engine's automatic column header repetition becomes thead, which is the single cleanest translation in the list.
  • Everything CSS offers beyond the designer's property panel is new.

What changes without anything erroring

The dangerous list. Each of these produces a different document and no diagnostic, so none of them are caught by a test that only checks the render succeeded.

  • Everything visual, because it is a rebuild.
  • Every computed value, because the expression language stops running. Totals, counts and running sums have to be produced by your code and will silently be absent or zero until they are.
  • Group behaviour at page boundaries, which the engine handled by its own rules and CSS handles by yours.
  • Page count.

What to diff before cutting over

Diff the numbers, not the layout. Take the totals, subtotals and counts from a set of old reports and assert them against the new ones, because those came from the expression language and are the thing most likely to be quietly wrong.

The one thing that always breaks

The computed variables. Report files carry sums, counts and running totals as expressions evaluated by the engine, they are invisible in the data your code passes in, and they are frequently the numbers the report exists to show. Rebuilding the layout without noticing them produces a report that looks right and whose totals are missing.

Frequently asked

Do I have to rewrite my templates to leave JasperReports?

Effectively yes, and it is better to plan for that than to discover it. The old tool did not have HTML templates to port, so the document has to be expressed as markup for the first time. The value in the old code is the data layer underneath the drawing, and that part survives untouched.

Can I run both for a while?

Yes, and it is the safest way to do it. Put both behind one internal function that takes your data and returns bytes, switch on an environment variable, and run the new path on real traffic while the old one still serves. You get a diff on real documents rather than on fixtures, and you keep a way back that does not involve a deploy.

What about the documents already generated?

Nothing here changes them. They are files that already exist. What is worth deciding before the cutover is whether a regenerated document has to match the original byte for byte or merely say the same thing, because for anything with a legal or audit character the answer is usually to keep the original file rather than to be able to reproduce it.

Other migrations

The nearest neighbours first, then others that started from the same kind of tool, because the model matters more than the language.

Render one of your existing documents through the playground before changing any code. That comparison is the whole of the risk assessment for this migration.