JRXML Report Design

This content was generated with the assistance of AI and should be verified against the official documentation before being relied on in production.

The reference material consulted while preparing these pages is listed in the section bibliography.

Baseline date: 2026-10-09. A JasperReports template is a description of a page, not a program: it says how big the page is, which bands exist, and which elements sit at which coordinates inside each band. The engine does the rest, filling the detail band once per record, breaking pages, stretching text and printing the footers. This page covers that description for JasperReports 7.0.8, using the monthly sales report of the Bookshelf Billing service as the example. Where values come from (parameters, fields, variables) is the subject of Expressions, Parameters, Fields & Variables, and grouping of Groups, Sorting & Filtering. The place of the design in the design, compile, fill and export pipeline is explained in JasperReports Architecture & Lifecycle, and the Maven setup in Getting Started with Spring Boot.

The example on this page was compiled, filled and exported to PDF with Java 21 and JasperReports 7.0.8, and the PDF was read back to check which bands printed on which page. A few results (what fails, and the exact limits) come from that run and are marked as such.

The v7 JRXML format

JRXML is the XML file format of a JasperReports design. Version 7.0 changed it: the files are now read with Jackson XML instead of the old SAX digester, the root element has no XML namespace, there is no DOCTYPE and no schema reference, and every report element is a generic <element> whose kind attribute says what it is. A text field that was written as a textField element with a nested reportElement and textFieldExpression in a 6.x file is, in 7.0, a single <element kind="textField" x="..." ...> with an <expression> child. Most attributes that used to be isSomething booleans lost the prefix (titleNewPage, summaryNewPage, floatColumnFooter), and several attributes became enums with readable names (hTextAlign="Right", positionType="Float").

The older books consulted for this section describe the earlier format. The JasperReports book of the corpus (B2, written for JasperReports 1.x and 2.x) and the Ultimate Guide (B3, for versions that predate 1.0) both define the design through a DTD, jasperreport.dtd, which became an XSD in 3.x and is replaced altogether in 7.0. Their element lists, attribute names and the namespace and DOCTYPE lines at the top of their examples do not apply to a 7.0 design, and the old isSplitAllowed boolean they use for splitting bands is now splitType (finding O19, see below). Nothing from those books is reproduced here.

Two practical consequences follow. First, a JRXML, JRTX or compiled .jasper file written for 6.x cannot be loaded by 7.0: as a check, a minimal 6.x file (namespace, reportElement, staticText) fails in 7.0.8 with a JRException whose message is "Unable to load report". The official route is to open and save such files with Jaspersoft Studio 7, which reads the old formats and writes v7 JRXML; the conversion tool was not run for this page, so check the result of a conversion in the designer rather than trusting it blindly. Second, an AI assistant or a snippet from a web page that shows <textField> or <reportElement> is describing 6.x and will not compile.

A complete design

The report below uses every band the engine knows, apart from the group bands covered on the groups page, and one of each common element except break and generic, which are shown further down. It is the design of the sales report that lists the month’s sales as a table. The logo and the month come in as parameters, the rows as fields, and the grand total is a variable computed by the engine.

<jasperReport name="sales-design" language="java"
              pageWidth="595" pageHeight="842" orientation="Portrait"
              columnCount="1" columnWidth="515"
              leftMargin="40" rightMargin="40" topMargin="50" bottomMargin="40"
              whenNoDataType="NoDataSection">
  <parameter name="LOGO" class="java.awt.Image"/>
  <parameter name="MONTH" class="java.lang.String"/>
  <field name="title" class="java.lang.String"/>
  <field name="category" class="java.lang.String"/>
  <field name="quantity" class="java.lang.Integer"/>
  <field name="amount" class="java.math.BigDecimal"/>
  <variable name="grandTotal" class="java.math.BigDecimal" calculation="Sum">
    <expression><![CDATA[$F{amount}]]></expression>
  </variable>
  <background height="752">
    <element kind="staticText" x="100" y="280" width="315" height="60" fontSize="48" bold="true"
             forecolor="#EEEEEE" hTextAlign="Center" rotation="None">
      <text><![CDATA[DRAFT]]></text>
    </element>
  </background>
  <title height="70">
    <element kind="image" x="0" y="0" width="60" height="60" scaleImage="RetainShape">
      <expression><![CDATA[$P{LOGO}]]></expression>
    </element>
    <element kind="staticText" x="70" y="0" width="445" height="30" fontSize="20" bold="true">
      <text><![CDATA[Bookshelf sales report]]></text>
    </element>
    <element kind="textField" x="70" y="34" width="445" height="20" fontSize="12">
      <expression><![CDATA["Period: " + $P{MONTH}]]></expression>
    </element>
  </title>
  <pageHeader height="24">
    <element kind="textField" x="0" y="4" width="515" height="16" fontSize="9" hTextAlign="Right">
      <expression><![CDATA["Bookshelf Billing - " + $P{MONTH}]]></expression>
    </element>
  </pageHeader>
  <columnHeader height="22">
    <element kind="rectangle" x="0" y="0" width="515" height="22" backcolor="#DDE6F5" mode="Opaque" radius="0"/>
    <element kind="staticText" x="4" y="3" width="260" height="16" bold="true"><text><![CDATA[Title]]></text></element>
    <element kind="staticText" x="270" y="3" width="110" height="16" bold="true"><text><![CDATA[Category]]></text></element>
    <element kind="staticText" x="385" y="3" width="40" height="16" bold="true" hTextAlign="Right"><text><![CDATA[Qty]]></text></element>
    <element kind="staticText" x="430" y="3" width="80" height="16" bold="true" hTextAlign="Right"><text><![CDATA[Amount]]></text></element>
  </columnHeader>
  <detail>
    <band height="20" splitType="Prevent">
      <element kind="textField" x="4" y="2" width="260" height="16" textAdjust="StretchHeight"
               stretchType="ContainerHeight">
        <expression><![CDATA[$F{title}]]></expression>
      </element>
      <element kind="textField" x="270" y="2" width="110" height="16" positionType="Float">
        <expression><![CDATA[$F{category}]]></expression>
      </element>
      <element kind="textField" x="385" y="2" width="40" height="16" hTextAlign="Right" pattern="#,##0">
        <expression><![CDATA[$F{quantity}]]></expression>
      </element>
      <element kind="textField" x="430" y="2" width="80" height="16" hTextAlign="Right" pattern="#,##0.00">
        <expression><![CDATA[$F{amount}]]></expression>
      </element>
    </band>
    <band height="1">
      <element kind="line" x="0" y="0" width="515" height="1" stretchType="NoStretch">
        <pen lineWidth="0.5" lineColor="#999999"/>
      </element>
    </band>
  </detail>
  <columnFooter height="20">
    <element kind="ellipse" x="0" y="4" width="12" height="12" backcolor="#2E7D32" mode="Opaque"/>
    <element kind="staticText" x="18" y="2" width="300" height="16" fontSize="9">
      <text><![CDATA[Amounts in EUR, VAT excluded]]></text>
    </element>
  </columnFooter>
  <pageFooter height="24">
    <element kind="textField" x="0" y="4" width="515" height="16" fontSize="9" hTextAlign="Center">
      <expression><![CDATA["Page " + $V{PAGE_NUMBER} + " (continues)"]]></expression>
    </element>
  </pageFooter>
  <lastPageFooter height="40">
    <element kind="textField" x="0" y="4" width="515" height="16" fontSize="9" hTextAlign="Center">
      <expression><![CDATA["Page " + $V{PAGE_NUMBER} + " (last)"]]></expression>
    </element>
    <element kind="staticText" x="0" y="22" width="515" height="14" fontSize="8" hTextAlign="Center">
      <text><![CDATA[Bookshelf Billing, generated report]]></text>
    </element>
  </lastPageFooter>
  <summary height="90">
    <element kind="frame" x="0" y="10" width="515" height="60" mode="Opaque" backcolor="#F4F4F4">
      <box>
        <pen lineWidth="0.75" lineColor="#333333"/>
      </box>
      <element kind="staticText" x="10" y="8" width="200" height="20" bold="true"><text><![CDATA[Grand total]]></text></element>
      <element kind="textField" x="300" y="8" width="200" height="20" bold="true" hTextAlign="Right" pattern="#,##0.00">
        <expression><![CDATA[$V{grandTotal}]]></expression>
      </element>
      <element kind="textField" x="10" y="32" width="490" height="16" fontSize="9">
        <expression><![CDATA["Rows: " + $V{REPORT_COUNT}]]></expression>
      </element>
    </element>
  </summary>
  <noData height="60">
    <element kind="staticText" x="0" y="20" width="515" height="24" fontSize="14" hTextAlign="Center">
      <text><![CDATA[No sales for this period]]></text>
    </element>
  </noData>
</jasperReport>

Everything in the file follows one pattern. The <jasperReport> element carries the page format and the policies. Each fixed band (title, pageHeader, columnHeader, columnFooter, pageFooter, lastPageFooter, summary, noData, background) is a child with a height attribute and the elements directly inside it, in v7 there is no extra <band> wrapper. Only detail, and the group headers and footers, wrap their content in <band height="...">, because they can hold several bands. Elements are <element kind="..."> with x, y, width and height in points, relative to the band’s top left corner inside the margins. The <expression> of a text field or image is Java by default (language="java" on the root; the compiler for that is jasperreports-jdt, see the Maven setup below).

The driver below compiles the file, fills it from a list of beans and writes the PDF. The row class is a plain JavaBean: the bean data source reads properties through getters, so a Java record is rejected as a row type (checked with 7.0.8), and the parameter map must be a mutable HashMap, because Map.of is rejected as the parameters map of fillReport.

package bookshelf;

import java.math.BigDecimal;

/** JavaBean row: JRBeanCollectionDataSource needs getters, a record is not accepted. */
public class Sale {
    private final String title;
    private final String category;
    private final int quantity;
    private final BigDecimal amount;

    public Sale(String title, String category, int quantity, BigDecimal amount) {
        this.title = title;
        this.category = category;
        this.quantity = quantity;
        this.amount = amount;
    }

    public String getTitle() { return title; }
    public String getCategory() { return category; }
    public int getQuantity() { return quantity; }
    public BigDecimal getAmount() { return amount; }
}
package bookshelf;

import java.awt.Color;
import java.awt.Graphics2D;
import java.awt.image.BufferedImage;
import java.io.InputStream;
import java.math.BigDecimal;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import net.sf.jasperreports.engine.JasperCompileManager;
import net.sf.jasperreports.engine.JasperExportManager;
import net.sf.jasperreports.engine.JasperFillManager;
import net.sf.jasperreports.engine.JasperPrint;
import net.sf.jasperreports.engine.JasperReport;
import net.sf.jasperreports.engine.data.JRBeanCollectionDataSource;

public class SalesDesignDemo {

    public static void main(String[] args) throws Exception {
        int rows = args.length > 0 ? Integer.parseInt(args[0]) : 80;
        try (InputStream jrxml = SalesDesignDemo.class.getResourceAsStream("/reports/sales-design.jrxml")) {
            JasperReport report = JasperCompileManager.compileReport(jrxml);

            List<Sale> sales = new ArrayList<>();
            for (int i = 1; i <= rows; i++) {
                sales.add(new Sale("Book number " + i, i % 2 == 0 ? "Fiction" : "Science",
                        i % 5 + 1, new BigDecimal("12.50").multiply(BigDecimal.valueOf(i))));
            }

            Map<String, Object> params = new HashMap<>(); // Map.of is rejected by fillReport
            params.put("LOGO", logo());
            params.put("MONTH", "2026-09");

            JasperPrint print = JasperFillManager.fillReport(report, params, new JRBeanCollectionDataSource(sales));
            Path out = Path.of("sales-design-" + rows + ".pdf");
            Files.write(out, JasperExportManager.exportReportToPdf(print));
            System.out.println(out + ": " + print.getPages().size() + " pages");
        }
    }

    private static BufferedImage logo() {
        BufferedImage image = new BufferedImage(60, 60, BufferedImage.TYPE_INT_RGB);
        Graphics2D g = image.createGraphics();
        g.setColor(new Color(0x1F5FA6));
        g.fillRect(0, 0, 60, 60);
        g.dispose();
        return image;
    }
}

The Maven coordinates are the JasperReports ones used throughout this section, all at 7.0.8. The jasperreports-pdf module holds the PDF exporter, jasperreports-fonts the bundled DejaVu fonts and jasperreports-jdt the Eclipse compiler that compiles the Java expressions (see the Getting Started page for why it is needed).

<properties>
    <maven.compiler.release>21</maven.compiler.release>
    <jasperreports.version>7.0.8</jasperreports.version>
</properties>
<dependencies>
    <dependency>
        <groupId>net.sf.jasperreports</groupId>
        <artifactId>jasperreports</artifactId>
        <version>${jasperreports.version}</version>
    </dependency>
    <dependency>
        <groupId>net.sf.jasperreports</groupId>
        <artifactId>jasperreports-pdf</artifactId>
        <version>${jasperreports.version}</version>
    </dependency>
    <dependency>
        <groupId>net.sf.jasperreports</groupId>
        <artifactId>jasperreports-fonts</artifactId>
        <version>${jasperreports.version}</version>
    </dependency>
    <dependency>
        <groupId>net.sf.jasperreports</groupId>
        <artifactId>jasperreports-jdt</artifactId>
        <version>${jasperreports.version}</version>
    </dependency>
</dependencies>

Running java bookshelf.SalesDesignDemo 80 (rows as argument, 80 by default) produced a 3-page PDF, 0 rows a 1-page PDF with only the noData text, and 3 rows a single page. Derived from the JasperReports sample on creating reports and the JasperCompileManager API.

Page format, columns and print order

The attributes of <jasperReport> set the page and the grid inside it.

Attributes Meaning

pageWidth, pageHeight, orientation

The page size in points (595 by 842 is A4 portrait) and its orientation, Portrait or Landscape. The size and the orientation are stored separately: changing orientation does not swap the two numbers.

leftMargin, rightMargin, topMargin, bottomMargin

The margins. All bands live inside them. The usable height is the page height minus top and bottom margins, and the usable width the page width minus left and right margins.

columnCount, columnWidth, columnSpacing

The number of columns, the width of each and the gap between them. columnWidth is required even for a single column, and the columns and the margins have to fit the page width (a design that does not fit fails to compile with "The columns and the margins do not fit the page width").

printOrder

Vertical (the default) fills the first column down the page, then the second; Horizontal places the records left to right across the columns, one row at a time, which is what labels and cards need.

titleNewPage, summaryNewPage, summaryWithPageHeaderAndFooter

Print the title on a page of its own, start the summary on a new page, and print the page header and footer on that summary page. All three compiled in 7.0.8.

floatColumnFooter

true lets the column footer float up right under the last detail instead of staying at the bottom of the column.

ignorePagination

true produces a single page as tall as the content needs, which suits HTML output and is rarely wanted for PDF.

whenNoDataType

What a report with no records produces, described in its own section below.

The bands are measured against the page. The sum of the band heights that appear together on a page, plus the margins, must fit the page height, and the compiler checks it. For the example above, with top margin 50 and bottom margin 40, the background can be at most 752 points tall: a background of the full page height 842 failed validation in 7.0.8 with "The background section and the margins do not fit the page height". The same check applies to the other fixed bands, so a very tall title or pageFooter is rejected at compile time, not at fill time.

The bands and where they print

Bands are the horizontal strips of the design. Each one has a fixed place in the page and a rule for when it prints, and the figure shows all of them on one page and on the pages of a longer report.

The bands of a JasperReports page: title, pageHeader, columnHeader, detail, summary, columnFooter and pageFooter or lastPageFooter, with the background behind them and the pages of a longer report
Band When it prints

background

On every page, behind everything else. It is the place for a watermark such as the "DRAFT" text of the example. In the run above it also appeared on the page produced by the noData section.

title

Once, at the top of the first page, before the page header. With titleNewPage="true" it takes a page of its own.

pageHeader

At the top of every page, below the title on the first page. In the example it is printed on all three pages.

columnHeader

At the top of every column of every page. The labels of a table belong here.

detail

Once for each record. A report may declare several <band> elements in detail: they print one after the other for each record, so a row and a separator line (as in the example) or a main row and a notes row can be separate bands, each with its own height and splitType.

columnFooter

At the bottom of every column, or directly under the last detail when floatColumnFooter is true.

pageFooter

At the bottom of every page, except the last page when a lastPageFooter is defined.

lastPageFooter

Replaces pageFooter on the last page. It exists so that the last page can carry a signature block or a legal note while the others carry only a page number. In the example the third page printed "Page 3 (last)", and the first two "Page n (continues)". A report that fits on one page has only a last page.

summary

Once, after the last detail, with the totals. If it does not fit it goes to the next page, and summaryNewPage forces that. In the checked output it came right after the last row, above the column footer, which stayed at the bottom.

noData

Printed instead of the whole report when there are no records and whenNoDataType is NoDataSection.

The group header and footer bands (groupHeader, groupFooter) sit around the detail bands of each group and are described in Groups, Sorting & Filtering.

Reports with no data

whenNoDataType decides what a report does when the data source has no records. There are four values, and the example was run with the fourth.

  • NoPages is the default. The result is a document with no pages, which is not a useful PDF, so a service should check print.getPages().isEmpty() before exporting or choose another value.

  • BlankPage produces one empty page.

  • AllSectionsNoDetail prints every section except the detail: title, headers, footers and summary appear with empty values. With the compiled test report that has a title and a summary, the filled print had exactly those two elements.

  • NoDataSection prints only the noData band, plus the background. This is the value the example uses: with 0 rows the PDF contained the background text and "No sales for this period", with no title, header or footer.

The choice matters for services: an empty month must still return a valid PDF if the contract of the endpoint says so, and NoDataSection is the way to say "nothing to report" inside the document.

Elements

Every element has the geometry attributes x, y, width and height, plus colours (forecolor, backcolor) and a mode that is Opaque or Transparent, and the optional printWhenExpression, positionType, stretchType, removeLineWhenBlank, printRepeatedValues and printInFirstWholeBand. The kinds used in a typical report are these.

kind What it is

staticText

Fixed text in a <text> child, such as a column heading. Font, size, bold and alignment (hTextAlign, vTextAlign) are attributes.

textField

Text computed by an <expression>, formatted with pattern (as in #,##0.00) and, when it can be longer than its box, with textAdjust="StretchHeight" so that the box grows with the text. The other values of textAdjust are CutText (the default) and ScaleFont. The evaluation of the expression can be delayed with evaluationTime, which is how "page X of Y" is written (see Expressions, Parameters, Fields & Variables).

image

A picture from an <expression> that returns a path, URL, InputStream, byte array or java.awt.Image (the example passes a BufferedImage as the LOGO parameter). scaleImage chooses between RetainShape, FillFrame, Clip, RealHeight and RealSize, and onErrorType between Error, Blank and Icon for images that cannot be loaded.

line

A straight line between two corners of its box, with direction TopDown or BottomUp, and its look in a <pen> child (lineWidth, lineColor, lineStyle).

rectangle

A box with optional radius for rounded corners, filled when mode="Opaque". The column header of the example is a shaded rectangle with the labels on top of it.

ellipse

An ellipse in its box, a circle when the box is square (the green dot in the example column footer).

frame

A container with child elements positioned relative to the frame and an optional <box> for borders and padding. A frame moves and stretches its children together; the summary of the example is a frame with a border and three children.

break

A page or column break placed between the elements of a band, with type="Page" or type="Column". It splits the band at its y, and everything below it continues on the next page or column, usually with a printWhenExpression to make it conditional.

generic

A placeholder for content produced by an extension, identified by a <genericType namespace="..." name="..."/> and a list of <parameter> children with expressions. It is the base that components such as barcodes and maps build on and is rarely written by hand.

The break and generic forms were checked with a separate throwaway design in 7.0.8. A break with type="Page" and a printWhenExpression of the form $V{REPORT_COUNT}.intValue() == 3 placed between two elements of a detail band produced a second page after the third record. A break placed on the last line of a band, after all its elements, had no visible effect, because there was nothing below it to move. A generic element with a genericType and one <parameter> compiled and filled without errors; whether it draws anything in PDF depends on an export handler for its type being registered by an extension, which was not checked.

<detail>
  <band height="40">
    <element kind="textField" x="0" y="0" width="515" height="18">
      <expression><![CDATA[$F{title}]]></expression>
    </element>
    <element kind="break" x="0" y="20" width="515" height="1" type="Page">
      <printWhenExpression><![CDATA[$V{REPORT_COUNT}.intValue() == 3]]></printWhenExpression>
    </element>
    <element kind="staticText" x="0" y="22" width="515" height="16">
      <text><![CDATA[after break]]></text>
    </element>
  </band>
</detail>

The rotation attribute turns text by 90 degrees (Left or Right) or upside down (UpsideDown); the example sets rotation="None" on the watermark only to show the attribute. See the rotation sample.

Stretching and positioning

The height written in the design is the minimum. A text field with textAdjust="StretchHeight" grows when its text needs more lines, and the engine then has to decide what happens to the other elements and to the band itself. Two attributes of every element control that.

stretchType says how an element follows the growth of something else.

  • NoStretch (the default) keeps the height written in the design.

  • ElementGroupHeight and ElementGroupBottom stretch it with the elements of its group, the ones that overlap it.

  • ContainerHeight and ContainerBottom stretch it with the band or frame that holds it. This is how a vertical line or a cell background keeps the full height of a row when the title in that row wraps.

positionType says how an element moves when elements above it grow.

  • FixRelativeToTop (the default) keeps its distance from the top of the band.

  • Float moves it down by the amount that the elements above it have stretched, so it never overlaps them.

  • FixRelativeToBottom keeps its distance from the bottom of the band.

In the example the title uses textAdjust="StretchHeight" and stretchType="ContainerHeight", and the category uses positionType="Float". To confirm the effect, a row with a title long enough to wrap onto four lines was filled: the band grew to fit them, the next row started below it, and the page layout stayed valid. Another attribute, removeLineWhenBlank, removes the vertical space of an element that evaluates to empty, which is useful for optional address lines.

Derived from the stretch sample.

Splitting bands across pages

A detail band that does not fit in the space left on the page can be split or moved. splitType on a band controls that, with three values.

  • Stretch is the default: the band may be split, and the elements that stretch decide where; the API page below states the exact rule.

  • Prevent forbids splitting: the whole band moves to the next page, unless it is taller than any page can hold.

  • Immediate allows the band to be split at once, at any point.

splitType replaces the boolean isSplitAllowed of the books and of 6.x designs (finding O19): the three values express what the boolean could not. Rows of a table normally use Prevent, as in the example, so that a record never has its text cut by a page boundary; a very tall band that must flow across pages uses Stretch or Immediate.

The element attribute printWhenDetailOverflows makes an element print again on the continuation when its band overflows to the next page. Derived from the horizontal layout sample, the no-report sample and the SplitTypeEnum API.

Converting v6 files

Moving a 6.x project to 7.0 touches every design. The designs and style templates (JRXML, JRTX) must be converted, and any .jasper file stored in the repository must be recompiled from a converted JRXML. The conversion to the new format is done in Jaspersoft Studio 7, as stated by the project. After conversion, review these points, which are the ones that changed in the format.

  • The root element has no namespace or schema, and each report element is an <element kind="...">.

  • Fixed bands are direct children with a height, and splitType replaces isSplitAllowed.

  • The is prefix disappeared from many booleans and several text options became enums.

  • The Java classes moved too (for example the PDF exporter is net.sf.jasperreports.pdf.JRPdfExporter in 7.0), see JasperReports Architecture & Lifecycle.

A good habit is to keep the JRXML as the source of truth in src/main/resources/reports, compile it in the application (as the driver above does) or at build time, and never commit compiled .jasper files.

Where to go next