JasperReports scriptlet
last modified February 12, 2024
In this article 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.
<?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="report" topMargin="20" bottomMargin="20"> <scriptlet name="MyScriptlet" class="com.zetcode.MyScriptlet"/> <parameter name="vals" 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.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 @Grab(group='net.sf.jasperreports', module='jasperreports', version='6.21.0') @Grab(group='org.apache.commons', module='commons-math3', version='3.6.1') @Grab(group='com.github.librepdf', module='openpdf', version='1.3.39') import java.util.List import net.sf.jasperreports.engine.JRDefaultScriptlet import net.sf.jasperreports.engine.JREmptyDataSource import net.sf.jasperreports.engine.JasperCompileManager import net.sf.jasperreports.engine.JasperExportManager import net.sf.jasperreports.engine.JasperFillManager import net.sf.jasperreports.renderers.JCommonDrawableRendererImpl import org.apache.commons.math3.stat.descriptive.DescriptiveStatistics // Report generation def xmlFile = "report.xml" def jrReport = JasperCompileManager.compileReport(xmlFile) def vals = [1.2, 1.8, -1.2, 0.9, 1.1, 3.5, -2.7] def params = [:] params.put("vals", vals) def jrPrint = JasperFillManager.fillReport(jrReport, params, new JREmptyDataSource()) JasperExportManager.exportReportToPdfFile(jrPrint, "report.pdf") // Scriptlet class class MyScriptlet extends JRDefaultScriptlet { private DescriptiveStatistics stats void afterReportInit() { def vals = getParameterValue("vals") stats = new DescriptiveStatistics() vals.forEach((val) -> stats.addValue(val)) } void afterDetailEval() { setVariableValue("gmean", stats.getMean()) } }
The Groovy script generates the report.
def vals = [1.2, 1.8, -1.2, 0.9, 1.1, 3.5, -2.7]
These values are our interest rates.
params.put("vals", vals)
The list is placed into the parameters. The list maps to the <parameter
name="vals" class="java.util.List"/>
element created in the report.
class MyScriptlet extends JRDefaultScriptlet {
The scriptlet derives from the JRDefaultScriptlet
. It provides
default empty implementations for scriptlet events.
private DescriptiveStatistics stats void afterReportInit() { def vals = getParameterValue("vals") stats = new DescriptiveStatistics() vals.forEach((val) -> stats.addValue(val)) }
After the report has been initialized, we get the vals
parameter
containing the interest rate values and insert them into the
DescriptiveStatistics
.
void afterDetailEval() { setVariableValue("gmean", stats.getMean()) }
After the afterDetailEval
event, the geometric mean is calculated
and set to the gmean
variable.
Chart scriptlet
The following application creates a pie chart. It uses the JFreeChart library.
<?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="report" pageWidth="595" pageHeight="842" columnWidth="555" leftMargin="20" rightMargin="20" topMargin="20" bottomMargin="20"> <scriptlet name="MyScriptlet" class="com.zetcode.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.MyScriptlet" />
The scriptlet is a Groovy 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 @Grab(group='net.sf.jasperreports', module='jasperreports', version='6.21.0') @Grab(group='com.github.librepdf', module='openpdf', version='1.3.39') 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.JRDefaultScriptlet import net.sf.jasperreports.renderers.JCommonDrawableRendererImpl import org.jfree.chart.ChartFactory import org.jfree.data.general.DefaultPieDataset import org.jfree.util.Rotation // Report generation def xmlFile = "report.xml" def jrReport = JasperCompileManager.compileReport(xmlFile) def langs = [ "Python": 30.2, "C#": 10.0, "Java": 17.5, "PHP": 8.5, "Clojure": 1.1] def params = ["langs": langs] def jrPrint = JasperFillManager.fillReport(jrReport, params, new JREmptyDataSource()) JasperExportManager.exportReportToPdfFile(jrPrint, "report.pdf") // Scriptlet class class MyScriptlet extends JRDefaultScriptlet { void afterReportInit() { def langs = getParameterValue("langs") def dataset = new DefaultPieDataset() langs.forEach(dataset::setValue) def chart = ChartFactory.createPieChart3D( "Computer languages", dataset, true, true, false ) def plot = 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)) } }
The script compiles the report template and creates a PDF file.
def langs = [ "Python": 30.2, "C#": 10.0, "Java": 17.5, "PHP": 8.5, "Clojure": 1.1]
The values in this map are going to be displayed in the pie chart.
def params = ["langs": langs]
The data is passed as a langs
parameter.
class MyScriptlet extends JRDefaultScriptlet {
This scriptlet retrieves the data from the langs
parameter and
generates a pie chart. The chart is set to the report template variable.
def langs = getParameterValue("langs")
After the report has been initialized, we get the langs
parameter
containing the chart data.
def dataset = new DefaultPieDataset() langs.forEach(dataset::setValue)
The data is set to the DefaultPieDataset
.
def chart = ChartFactory.createPieChart3D( "Computer languages", dataset, true, true, false ) def plot = 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.
In this article we have worked with scriptlets; we have calculated a geometric mean from interest rates and generated a 3D pie chart.