ZetCode

JasperReports multiple data sources

last modified February 12, 2024

JasperReporte data sources in a s multiple data sources tutorial shows how use multiplreport generated with JasperReports library.

JasperReports is an open-source reporting library. It can create reports in various formats including PDF, HTML, XLS, or CSV. JasperReports creates page-oriented, ready-to-print documents.

JasperReports multiple data sources example

The following application displays data from two different data sources in a report.

pom.xml
src
└── main
    ├── java
    │   └── com
    │       └── zetcode
    │           ├── model
    │           │   ├── Car.java
    │           │   └── Country.java
    │           └── main
    │               ├── CommandLineRunner.java
    │               └── JasperMultipleDataSources.java
    └── resources
        └── report2.xml

This is the project structure.

pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
         http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.zetcode</groupId>
    <artifactId>multipledatasets</artifactId>
    <version>1.0-SNAPSHOT</version>

    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <maven.compiler.source>11</maven.compiler.source>
        <maven.compiler.target>11</maven.compiler.target>
        <exec.mainClass>com.zetcode.main.CommandLineRunner</exec.mainClass>
    </properties>

    <dependencies>

        <dependency>
            <groupId>net.sf.jasperreports</groupId>
            <artifactId>jasperreports</artifactId>
            <version>6.9.0</version>
        </dependency>

    </dependencies>

</project>

The Maven pom.xml file contains the jasperreports dependency.

com/zetcode/model/Car.java
package com.zetcode.model;

public class Car {

    private Long id;
    private String name;
    private int price;

    public Car() {}

    public Car(Long id, String name, int price) {
        this.id = id;
        this.name = name;
        this.price = price;
    }

    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getPrice() {
        return price;
    }

    public void setPrice(int price) {
        this.price = price;
    }

    @Override
    public String toString() {
        return "Car{" + "id=" + id + ", name=" +
                name + ", price=" + price + '}';
    }
}

This is a Car bean class. It contains car id, name, and price attributes.

com/zetcode/model/Country.java
package com.zetcode.model;

public class Country {

    private Long id;
    private String name;
    private int population;

    public Country(Long id, String name, int population) {
        this.id = id;
        this.name = name;
        this.population = population;
    }

    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getPopulation() {
        return population;
    }

    public void setPopulation(int population) {
        this.population = population;
    }
}

This is a Country bean class. It contains country id, name, and population attributes.

src/resources/report2.xml
<?xml version = "1.0" encoding = "UTF-8"?>
<!DOCTYPE jasperReport PUBLIC "//JasperReports//DTD Report Design//EN"
   "http://jasperreports.sourceforge.net/dtds/jasperreport.dtd">

<jasperReport xmlns="http://jasperreports.sourceforge.net/jasperreports"
              xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
              xsi:schemaLocation="http://jasperreports.sourceforge.net/jasperreports
   http://jasperreports.sourceforge.net/xsd/jasperreport.xsd"
              name="freport" pageWidth="595" pageHeight="842"
              columnWidth="555" leftMargin="20" rightMargin="20"
              topMargin="20" bottomMargin="20">

<style name="field" fontSize="11" />
<style name="textRight" style="field" hAlign="Right" />

<subDataset name="dataset1">
    <field name="id" class="java.lang.Long"/>
    <field name="name" class="java.lang.String"/>
    <field name="price" class="java.lang.Integer"/>
</subDataset>

<subDataset name="dataset2">
    <field name="id" class="java.lang.Long"/>
    <field name="name" class="java.lang.String"/>
    <field name="population" class="java.lang.Integer"/>
</subDataset>

<parameter name="datasource1" class="java.util.List"/>
<parameter name="datasource2" class="java.util.List"/>

<detail>
    <band height="15">

        <componentElement>
            <reportElement x="0" y="0" width="100" height="15"/>
            <jr:list xmlns:jr="http://jasperreports.sourceforge.net/jasperreports/components"
                        xsi:schemaLocation="http://jasperreports.sourceforge.net/jasperreports/components
                                            http://jasperreports.sourceforge.net/xsd/components.xsd">

                <datasetRun subDataset="dataset2">
                    <dataSourceExpression><![CDATA[new net.sf.jasperreports.engine.data.JRBeanCollectionDataSource($P{datasource2})]]></dataSourceExpression>
                </datasetRun>

                <jr:listContents height="15" width="220">
                    <textField>
                        <reportElement x="0" y="0" width="20" height="15" style="field" />

                        <textElement />

                        <textFieldExpression class="java.lang.Long"><![CDATA[$F{id}]]></textFieldExpression>
                    </textField>

                    <textField>
                        <reportElement x="50" y="0" width="80" height="15" style="field" />

                        <textElement />

                        <textFieldExpression class="java.lang.String"><![CDATA[$F{name}]]></textFieldExpression>
                    </textField>

                    <textField>
                        <reportElement x="130" y="0" width="80" height="15" style="textRight" />
                        <textElement />

                        <textFieldExpression class="java.lang.Integer"><![CDATA[$F{population}]]></textFieldExpression>
                    </textField>

                </jr:listContents>
            </jr:list>
        </componentElement>

        <componentElement>
            <reportElement x="250" y="0" width="100" height="15"/>
            <jr:list xmlns:jr="http://jasperreports.sourceforge.net/jasperreports/components"
                        xsi:schemaLocation="http://jasperreports.sourceforge.net/jasperreports/components
                                            http://jasperreports.sourceforge.net/xsd/components.xsd">

                <datasetRun subDataset="dataset1">
                    <dataSourceExpression><![CDATA[new net.sf.jasperreports.engine.data.JRBeanCollectionDataSource($P{datasource1})]]></dataSourceExpression>
                </datasetRun>

                <jr:listContents height="15" width="220">
                    <textField>
                        <reportElement x="0" y="0" width="20" height="15" style="field" />

                        <textElement />

                        <textFieldExpression class="java.lang.Long"><![CDATA[$F{id}]]></textFieldExpression>
                    </textField>

                    <textField>
                        <reportElement x="50" y="0" width="80" height="15" style="field" />

                        <textElement />

                        <textFieldExpression class="java.lang.String"><![CDATA[$F{name}]]></textFieldExpression>
                    </textField>

                    <textField>
                        <reportElement x="130" y="0" width="80" height="15" style="textRight" />
                        <textElement />

                        <textFieldExpression class="java.lang.Integer"><![CDATA[$F{price}]]></textFieldExpression>
                    </textField>

                </jr:listContents>
            </jr:list>
        </componentElement>

    </band>
</detail>

</jasperReport>

This is the report template file. The report contains two list components. The list components load data from the list parameters passed to the report.

<subDataset name="dataset1">
    <field name="id" class="java.lang.Long"/>
    <field name="name" class="java.lang.String"/>
    <field name="price" class="java.lang.Integer"/>
</subDataset>

<subDataset name="dataset2">
    <field name="id" class="java.lang.Long"/>
    <field name="name" class="java.lang.String"/>
    <field name="population" class="java.lang.Integer"/>
</subDataset>

We have two subdatasets; each of them has three fields. The fields are mapped to the attributes of the Java beans.

<parameter name="datasource1" class="java.util.List"/>
<parameter name="datasource2" class="java.util.List"/>

The report accepts two java.util.List parameters.

<componentElement>
    <reportElement x="0" y="0" width="100" height="15"/>
    <jr:list xmlns:jr="http://jasperreports.sourceforge.net/jasperreports/components"
...

There are two jr:list components in the report. Each subDataset is added to one list component.

<datasetRun subDataset="dataset2">
    <dataSourceExpression><![CDATA[new net.sf.jasperreports.engine.data.JRBeanCollectionDataSource($P{datasource2})]]></dataSourceExpression>
</datasetRun>

The subDataset is executed in the datasetRun tag. The list parameter is passed to the JRBeanCollectionDataSource. We refer to the parameter with the $P{} syntax.

<jr:listContents height="15" width="220">
    <textField>
        <reportElement x="0" y="0" width="20" height="15" style="field" />

        <textElement />

        <textFieldExpression class="java.lang.Long"><![CDATA[$F{id}]]></textFieldExpression>
    </textField>
...

The fields are passed to the textField components, which are added to the jr:listContents tag. The field data is shown with the $F{} syntax.

com/zetcode/main/JasperMultipleDataSources.java
package com.zetcode.main;

import com.zetcode.model.Car;
import com.zetcode.model.Country;
import net.sf.jasperreports.engine.JREmptyDataSource;
import net.sf.jasperreports.engine.JRException;
import net.sf.jasperreports.engine.JasperCompileManager;
import net.sf.jasperreports.engine.JasperExportManager;
import net.sf.jasperreports.engine.JasperFillManager;

import java.util.ArrayList;
import java.util.HashMap;

public class JasperMultipleDataSources {

    public void start() throws JRException {

        var xmlFile = "src/main/resources/report2.xml";
        var jasperReport = JasperCompileManager.compileReport(xmlFile);

        var cars = new ArrayList<>();

        cars.add(new Car(1L, "Audi", 52642));
        cars.add(new Car(2L, "Mercedes", 57127));
        cars.add(new Car(3L, "Skoda", 9000));
        cars.add(new Car(4L, "Volvo", 29000));
        cars.add(new Car(5L, "Bentley", 350000));
        cars.add(new Car(6L, "Citroen", 21000));
        cars.add(new Car(7L, "Hummer", 41400));
        cars.add(new Car(8L, "Volkswagen", 21600));

        var countries = new ArrayList<Country>();

        countries.add(new Country(1L, "China", 1382050000));
        countries.add(new Country(2L, "India", 1313210000));
        countries.add(new Country(3L, "USA", 324666000));
        countries.add(new Country(4L, "Indonesia", 260581000));
        countries.add(new Country(5L, "Brazil", 207221000));
        countries.add(new Country(6L, "Pakistan", 196626000));
        countries.add(new Country(7L, "Nigeria", 186988000));
        countries.add(new Country(8L, "Bangladesh", 162099000));

        var params = new HashMap<String, Object>();
        params.put("datasource1", cars);
        params.put("datasource2", countries);

        var jasperPrint = JasperFillManager.fillReport(jasperReport,
                params, new JREmptyDataSource());

        JasperExportManager.exportReportToPdfFile(jasperPrint,
                "src/main/resources/report2.pdf");
    }
}

The JasperMultipleDataSources creates a JasperPrint file from the data sources and the report2.xml template. JasperPrint represents a page-oriented document that can be viewed, printed, or exported to other formats.

var xmlFile = "src/main/resources/report2.xml";
var jasperReport = JasperCompileManager.compileReport(xmlFile);

We compile the XML template file into a JasperReport. JasperReport is a compiled template ready to be filled with data.

var cars = new ArrayList<>();

cars.add(new Car(1L, "Audi", 52642));
cars.add(new Car(2L, "Mercedes", 57127));
cars.add(new Car(3L, "Skoda", 9000));
...

This is a list of car objects.

var countries = new ArrayList<Country>();

countries.add(new Country(1L, "China", 1382050000));
countries.add(new Country(2L, "India", 1313210000));
countries.add(new Country(3L, "USA", 324666000));
...

This is a list of country objects.

var params = new HashMap<String, Object>();
params.put("datasource1", cars);
params.put("datasource2", countries);

The two lists are added to the params map.

var jasperPrint = JasperFillManager.fillReport(jasperReport,
    params, new JREmptyDataSource());

A JasperPrint object is created; an object that can be viewed, printed, or exported to other formats. The params map is passed to the JasperFillManager.fillReport() method. The main data source of the report has an empty data source.

JasperExportManager.exportReportToPdfFile(jprint,
        "src/main/resources/report2.pdf");

The JasperExportManager.exportReportToPdfFile() method exports the JasperPrint into a PDF file.

com/zetcode/main/CommandLineRunner.java
package com.zetcode.main;

public class CommandLineRunner {

    public static void main(String[] args) throws Exception {

        var app = new JasperMultipleDataSources();
        app.start();
    }
}

The CommandLineRunner sets up the application.

$ mvn compile
$ mvn exec:java

We compile and run the application.

In this article we have generated a PDF file report data from two different data sources.

Author

My name is Jan Bodnar and I am a passionate programmer with many years of programming experience. I have been writing programming articles since 2007. So far, I have written over 1400 articles and 8 e-books. I have over eight years of experience in teaching programming.

List all JasperReports tutorials.