JasperReports scriptlets
last modified July 13, 2020
In this tutorial, we work with JasperReport scriptlets.
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 in a simple and flexible manner.
Scriptlets are Java classes that provide additional functionality to JasperReports. We can use scriptlets when report expressions cannot execute more complex operations. Scriptlets are executed every time a report event occurs. Values of report variables can be affected through scriptlets.
Calculating a geometric mean
The following application calculates geometric mean of interest rates. The geometric mean is defined as the nth root of the product of n numbers. It is used in growth rates, like population growth or interest rates, where simple arithmetic mean does not give accurate results.
$ tree . ├── pom.xml └── src └── main ├── java │ └── com │ └── zetcode │ └── main │ ├── CommandLineRunner.java │ ├── JasperScriptletGeoMean.java │ └── MyScriptlet.java └── resources └── report2.xml
This is the project structure.
<?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>JasperScriptletGeoMean</artifactId> <version>1.0-SNAPSHOT</version> <packaging>jar</packaging> <properties> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <maven.compiler.source>1.8</maven.compiler.source> <maven.compiler.target>1.8</maven.compiler.target> </properties> <dependencies> <dependency> <groupId>net.sf.jasperreports</groupId> <artifactId>jasperreports</artifactId> <version>6.4.0</version> </dependency> <dependency> <groupId>org.apache.commons</groupId> <artifactId>commons-math3</artifactId> <version>3.6.1</version> </dependency> </dependencies> <name>JasperScriptletGeoMean</name> >/project>
The Maven pom.xml
file contains these dependencies:
jasperreports
and commons-math3
.
The jasperreports
dependency is the JasperReports library;
the commons-math3
library contains the formula for the geometric
mean.
<?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="report2" pageWidth="595" pageHeight="842" columnWidth="555" leftMargin="20" rightMargin="20" topMargin="20" bottomMargin="20"> <scriptlet name="MyScriptlet" class="com.zetcode.main.MyScriptlet" /> <parameter name="rets" class="java.util.List"/> <variable name="gmean" class="java.lang.Double"/> <summary> <band height="30"> <staticText> <reportElement x="0" y="0" width="90" height="15" /> <textElement /> <text><![CDATA[Geometric mean: ]]></text> </staticText> <textField> <reportElement x="100" y="0" width="200" height="15"/> <textElement /> <textFieldExpression class="java.lang.Double"> <![CDATA[$V{gmean}]]> </textFieldExpression> </textField> </band> </summary> </jasperReport>
This is the report template file. The template contains the summary band where
we have one variable: gmean
.
<scriptlet name="MyScriptlet" class="com.zetcode.main.MyScriptlet" />
A scriptlet is referenced with the <scriptlet />
tag.
It is a class that contains the calculation of the geometric mean.
<parameter name="rets" class="java.util.List"/> <variable name="gmean" class="java.lang.Double"/>
We have a parameter and a variable. The parameter is a list of interest rate values. The variable is the computed geometric mean.
<textFieldExpression class="java.lang.Double"> <![CDATA[$V{gmean}]]> </textFieldExpression>
In the <textFieldExpression>
tag we output the geometric mean.
package com.zetcode.main; import java.util.ArrayList; import java.util.HashMap; import java.util.Map; 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 net.sf.jasperreports.engine.JasperPrint; import net.sf.jasperreports.engine.JasperReport; public class JasperScriptletGeoMean { public void start() throws JRException { String xmlFile = "src/main/resources/report2.xml"; JasperReport jreport = JasperCompileManager.compileReport(xmlFile); ArrayList<Double> rets = new ArrayList<>(); rets.add(1.2); rets.add(1.8); rets.add(-1.2); rets.add(1.1); Map params = new HashMap(); params.put("rets", rets); JasperPrint jprint = JasperFillManager.fillReport(jreport, params, new JREmptyDataSource()); JasperExportManager.exportReportToPdfFile(jprint, "src/main/resources/report2.pdf"); } }
The JasperScriptletGeoMean
creates a JasperPrint
file from
the data source. JasperPrint
represents a page-oriented
document that can be viewed, printed, or exported to other formats. In our case,
it is going to be exported into a PDF file.
String xmlFile = "src/main/resources/table.xml"; JasperReport jreport = JasperCompileManager.compileReport(xmlFile);
We compile the XML template file into a JasperReport
.
JasperReport
is a compiled template ready to be filled
with data.
ArrayList<Double> rets = new ArrayList<>(); rets.add(1.2); rets.add(1.8); rets.add(-1.2); rets.add(1.1);
These values are our interest rates.
Map params = new HashMap(); params.put("rets", rets);
The ArrayList
is placed into the parameters. The list maps
to the <parameter name="rets" class="java.util.List"/>
element created in the report.
JasperPrint jprint = JasperFillManager.fillReport(jreport, params, new JREmptyDataSource());
A JasperPrint
object is created; an object that can be
viewed, printed, or exported to other formats.
JasperExportManager.exportReportToPdfFile(jprint, "src/main/resources/report2.pdf");
The JasperExportManager.exportReportToPdfFile
method
exports the JasperPrint
into a PDF file.
package com.zetcode.main; import java.util.List; import net.sf.jasperreports.engine.JRDefaultScriptlet; import net.sf.jasperreports.engine.JRScriptletException; import org.apache.commons.math3.stat.descriptive.DescriptiveStatistics; public class MyScriptlet extends JRDefaultScriptlet { private DescriptiveStatistics stats; @Override public void afterReportInit() throws JRScriptletException { List<Double> rets = (List<Double>) getParameterValue("rets"); stats = new DescriptiveStatistics(); rets.forEach((ret) -> { stats.addValue(ret); }); } @Override public void afterDetailEval() throws JRScriptletException { setVariableValue("gmean", stats.getMean()); } }
This is our scriptlet. It derives from the JRDefaultScriptlet
.
JRDefaultScriptlet
provides default empty implementations for scriptlet events.
@Override public void afterReportInit() throws JRScriptletException { List<Double> rets = (List<Double>) getParameterValue("rets"); stats = new DescriptiveStatistics(); rets.forEach((ret) -> { stats.addValue(ret); }); }
After the report has been initialized, we get the rets
parameter
containing the interest rate values and insert them into the DescriptiveStatistics
.
@Override public void afterDetailEval() throws JRScriptletException { setVariableValue("gmean", stats.getMean()); }
After the afterDetailEval
event, the geometric mean is calculated and set
to the gmean
variable.
package com.zetcode.main; public class CommandLineRunner { public static void main(String[] args) throws Exception { JasperScriptletGeoMean app = new JasperScriptletGeoMean(); app.start(); } }
The CommandLineRunner
sets up the application.
Creating a chart
The following application creates a pie chart. It uses the JFreeChart library.
$ tree . ├── pom.xml └── src ├── main │ ├── java │ │ └── com │ │ └── zetcode │ │ └── main │ │ ├── CommandLineRunner.java │ │ ├── JasperJFreeChart.java │ │ └── MyScriptlet.java │ └── resources │ └── report2.xml └── test └── java
This is the project structure.
<?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>JasperJFreeChart</artifactId> <version>1.0-SNAPSHOT</version> <packaging>jar</packaging> <properties> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <maven.compiler.source>1.8</maven.compiler.source> <maven.compiler.target>1.8</maven.compiler.target> </properties> <dependencies> <dependency> <groupId>net.sf.jasperreports</groupId> <artifactId>jasperreports</artifactId> <version>6.4.0</version> </dependency> </dependencies> <name>JasperJFreeChart</name> </project>
We only need the jasperreports
dependency; JFreeChart is already included
in this dependency.
<?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="report2" pageWidth="595" pageHeight="842" columnWidth="555" leftMargin="20" rightMargin="20" topMargin="20" bottomMargin="20"> <scriptlet name="MyScriptlet" class="com.zetcode.main.MyScriptlet" /> <parameter name="langs" class="java.util.Map"/> <variable name="Chart" class="net.sf.jasperreports.renderers.JCommonDrawableRendererImpl" calculation="System"/> <detail> <band height="430"> <image scaleImage="Clip" hAlign="Center"> <reportElement x="0" y="0" width="515" height="300" /> <imageExpression> <![CDATA[ $V{Chart} ]]> </imageExpression> </image> </band> </detail> </jasperReport>
In the report template template file we have the detail band where
we have the <image>
element, which displays the chart.
<scriptlet name="MyScriptlet" class="com.zetcode.main.MyScriptlet" />
The scriptlet is a Java class that creates the chart object.
<parameter name="langs" class="java.util.Map"/> <variable name="Chart" class="net.sf.jasperreports.renderers.JCommonDrawableRendererImpl" calculation="System"/>
We have a parameter and a variable. The parameter is a map of values to be displayed in the chart. The variable contains the chart object.
package com.zetcode.main; import java.util.HashMap; import java.util.Map; 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 net.sf.jasperreports.engine.JasperPrint; import net.sf.jasperreports.engine.JasperReport; public class JasperJFreeChart { public void start() throws JRException { String xmlFile = "src/main/resources/report2.xml"; JasperReport jreport = JasperCompileManager.compileReport(xmlFile); Map params = new HashMap(); params.put("langs", createData()); JasperPrint jprint = JasperFillManager.fillReport(jreport, params, new JREmptyDataSource()); JasperExportManager.exportReportToPdfFile(jprint, "src/main/resources/report2.pdf"); } private Map<String, Double> createData() { Map<String, Double> langs = new HashMap<>(); langs.put("Java", 43.2); langs.put("C#", 10.0); langs.put("C/C++", 17.5); langs.put("PHP", 32.5); langs.put("Clojure", 1.1); return langs; } }
The JasperJFreeChart
compiles the report template and creates
a PDF file.
Map params = new HashMap(); params.put("langs", createData());
The data is passed as a langs
parameter.
private Map<String, Double> createData() { Map<String, Double> langs = new HashMap<>(); langs.put("Java", 43.2); langs.put("C#", 10.0); langs.put("C/C++", 17.5); langs.put("PHP", 32.5); langs.put("Clojure", 1.1); return langs; }
The values in this map are going to be displayed in the pie chart.
package com.zetcode.main; import java.util.Map; import net.sf.jasperreports.engine.JRDefaultScriptlet; import net.sf.jasperreports.engine.JRScriptletException; import net.sf.jasperreports.renderers.JCommonDrawableRendererImpl; import org.jfree.chart.ChartFactory; import org.jfree.chart.JFreeChart; import org.jfree.chart.plot.PiePlot3D; import org.jfree.data.general.DefaultPieDataset; import org.jfree.util.Rotation; public class MyScriptlet extends JRDefaultScriptlet { @Override public void afterReportInit() throws JRScriptletException { Map<String, Double> langs = (Map<String, Double>) getParameterValue("langs"); DefaultPieDataset dataset = new DefaultPieDataset(); langs.forEach((k,v) -> { dataset.setValue(k, v); }); JFreeChart chart = ChartFactory.createPieChart3D( "Computer languages", dataset, true, true, false ); PiePlot3D plot = (PiePlot3D) chart.getPlot(); plot.setStartAngle(290); plot.setDirection(Rotation.CLOCKWISE); plot.setForegroundAlpha(0.5f); plot.setNoDataMessage("No data to display"); this.setVariableValue("Chart", new JCommonDrawableRendererImpl(chart)); } }
This scriptlet retrieves the data from the langs
parameter and
generates a pie chart. The chart is set to the report template variable.
Map<String, Double> langs = (Map<String, Double>) getParameterValue("langs");
After the report has been initialized, we get the langs
parameter
containing the chart data.
DefaultPieDataset dataset = new DefaultPieDataset(); langs.forEach((k,v) -> { dataset.setValue(k, v); });
The data is set to the DefaultPieDataset
.
JFreeChart chart = ChartFactory.createPieChart3D( "Computer languages", dataset, true, true, false ); PiePlot3D plot = (PiePlot3D) chart.getPlot(); plot.setStartAngle(290); plot.setDirection(Rotation.CLOCKWISE); plot.setForegroundAlpha(0.5f); plot.setNoDataMessage("No data to display");
A 3D pie chart is generated.
this.setVariableValue("Chart", new JCommonDrawableRendererImpl(chart));
The generated chart is set to the Chart
report template variable.
package com.zetcode.main; public class CommandLineRunner { public static void main(String[] args) throws Exception { JasperJFreeChart app = new JasperJFreeChart(); app.start(); } }
The CommandLineRunner
sets up the application.
In this tutorial, we have worked with scriptlets; we have calculated a geometric mean from interest rates and generated a 3D pie chart.