JasperReports handle null values
last modified February 12, 2024
In this article we show how to handle null values in JasperReports.
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.
Data sources often contain null values. These do not look good in our reports; therefore, we show how to replace them with empty strings or more descriptive messages such as 'N/A'.
<textField isBlankWhenNull="true">
In order to deal with null values, we can set the isBlankWhenNull
attribute of the textField
to true
.
$F{salary} != null ? $F{salary} : 'N/A'
Another option is to use a ternary operator in the textFieldExpression
.
class CleanData { static String removeNull(def oldval, def newval = '') { if (oldval == null) { newval } else { oldval } } }
Another option is to define an external method.
Example
In the next example, we use the isBlankWhenNull
attribute and
the ternary operator.
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') @Grab(group='com.h2database', module='h2', version='1.4.200') @GrabConfig(systemClassLoader=true) import net.sf.jasperreports.engine.JasperCompileManager import net.sf.jasperreports.engine.JasperFillManager import net.sf.jasperreports.engine.JasperExportManager import groovy.sql.Sql def xmlFile = 'report.xml' def jrReport = JasperCompileManager.compileReport(xmlFile) def createTable = ''' CREATE TABLE users(id INT PRIMARY KEY AUTO_INCREMENT, name VARCHAR(255), occupation VARCHAR(255), salary INT); INSERT INTO users(name, occupation, salary) VALUES('John Doe', 'gardener', NULL); INSERT INTO users(name, occupation, salary) VALUES('Roger Roe', 'driver', 940); INSERT INTO users(name, occupation, salary) VALUES('Roman Novy', 'programmer', 1980); INSERT INTO users(name, occupation, salary) VALUES('Lucia Biela', NULL, NULL); INSERT INTO users(name, occupation, salary) VALUES('Tomas Gerber', 'soldier', 1250); INSERT INTO users(name, occupation, salary) VALUES('Maria Smith', 'teacher', NULL); INSERT INTO users(name, occupation, salary) VALUES('Oleg Vasil', NULL, 2550); INSERT INTO users(name, occupation, salary) VALUES('Martin Krajci', 'optician', 2050); ''' def url = "jdbc:h2:mem:" Sql.withInstance(url) { sql -> sql.execute(createTable) def params = [:] def jPrint = JasperFillManager.fillReport(jrReport, params, sql.connection) JasperExportManager.exportReportToPdfFile(jPrint, "report.pdf") }
We define a users
table inside an in-memory H2 database.
def createTable = ''' CREATE TABLE users(id INT PRIMARY KEY AUTO_INCREMENT, name VARCHAR(255), occupation VARCHAR(255), salary INT); INSERT INTO users(name, occupation, salary) VALUES('John Doe', 'gardener', NULL); INSERT INTO users(name, occupation, salary) VALUES('Roger Roe', 'driver', 940); INSERT INTO users(name, occupation, salary) VALUES('Roman Novy', 'programmer', 1980); INSERT INTO users(name, occupation, salary) VALUES('Lucia Biela', NULL, NULL); INSERT INTO users(name, occupation, salary) VALUES('Tomas Gerber', 'soldier', 1250); INSERT INTO users(name, occupation, salary) VALUES('Maria Smith', 'teacher', NULL); INSERT INTO users(name, occupation, salary) VALUES('Oleg Vasil', NULL, 2550); INSERT INTO users(name, occupation, salary) VALUES('Martin Krajci', 'optician', 2050); '''
The table contains nulls in the occupation
and salary
columns.
<?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" language="groovy" name="report" topMargin="20" bottomMargin="20"> <queryString language="SQL"> <![CDATA[ SELECT id, name, occupation, salary from users ]]> </queryString> <field name="id" class="java.lang.Integer"/> <field name="name"/> <field name="occupation"/> <field name="salary" class="java.lang.Integer" /> <title> <band height="60"> <staticText> <reportElement x="0" y="0" width="595" height="35"/> <textElement textAlignment="Center"/> <text><![CDATA[Users]]></text> </staticText> </band> </title> <detail> <band height="30"> <textField> <reportElement x="0" y="0" width="25" height="25"/> <textFieldExpression class="java.lang.Integer"> <![CDATA[$F{id}]]> </textFieldExpression> </textField> <textField> <reportElement x="30" y="0" width="100" height="25"/> <textFieldExpression> <![CDATA[$F{name}]]> </textFieldExpression> </textField> <textField isBlankWhenNull="true"> <reportElement x="140" y="0" width="70" height="25"/> <textFieldExpression> <![CDATA[ $F{occupation} ]]> </textFieldExpression> </textField> <textField> <reportElement x="220" y="0" width="70" height="25"/> <textElement textAlignment="Right"/> <textFieldExpression class="java.lang.Integer"> <![CDATA[ $F{salary} != null ? $F{salary} : 'N/A' ]]> </textFieldExpression> </textField> </band> </detail> </jasperReport>
This is the report template.
<textField isBlankWhenNull="true"> <reportElement x="140" y="0" width="70" height="25"/> <textFieldExpression> <![CDATA[ $F{occupation} ]]> </textFieldExpression> </textField>
We set the isBlankWhenNull
to true
for the
occupation
field. Cells with null values will be empty.
<textField> <reportElement x="220" y="0" width="70" height="25"/> <textElement textAlignment="Right"/> <textFieldExpression class="java.lang.Integer"> <![CDATA[ $F{salary} != null ? $F{salary} : 'N/A' ]]> </textFieldExpression> </textField>
For the salary
field, we use a ternary operator. Nulls will be
replaced with N/A
strings.
In the next example we define an external method that handles nulls.
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') @Grab(group='net.sf.jasperreports', module='jasperreports-fonts', version='6.21.0') @Grab(group='com.h2database', module='h2', version='1.4.200') @GrabConfig(systemClassLoader=true) import net.sf.jasperreports.engine.JasperCompileManager import net.sf.jasperreports.engine.JasperFillManager import net.sf.jasperreports.engine.JasperExportManager import groovy.sql.Sql def xmlFile = 'report.xml' def jrReport = JasperCompileManager.compileReport(xmlFile) def createTable = ''' CREATE TABLE users(id INT PRIMARY KEY AUTO_INCREMENT, name VARCHAR(255), occupation VARCHAR(255), salary INT); INSERT INTO users(name, occupation, salary) VALUES('John Doe', 'gardener', NULL); INSERT INTO users(name, occupation, salary) VALUES('Roger Roe', 'driver', 940); INSERT INTO users(name, occupation, salary) VALUES('Roman Novy', 'programmer', 1980); INSERT INTO users(name, occupation, salary) VALUES('Lucia Biela', NULL, NULL); INSERT INTO users(name, occupation, salary) VALUES('Tomas Gerber', 'soldier', 1250); INSERT INTO users(name, occupation, salary) VALUES('Maria Smith', 'teacher', NULL); INSERT INTO users(name, occupation, salary) VALUES('Oleg Vasil', NULL, 2550); INSERT INTO users(name, occupation, salary) VALUES('Martin Krajci', 'optician', 2050); ''' def url = "jdbc:h2:mem:" Sql.withInstance(url) { sql -> sql.execute(createTable) def params = [:] def jPrint = JasperFillManager.fillReport(jrReport, params, sql.connection) JasperExportManager.exportReportToPdfFile(jPrint, "report.pdf") } class CleanData { static String removeNull(def oldval, def newval = '') { if (oldval == null) { newval } else { oldval } } }
In the Groovy code, we define the CleanData
and its
removeNull
method. It allows us to select a specific message to
be used instead of the null.
<?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" language="groovy" name="report" topMargin="20" bottomMargin="20"> <import value="com.zetcode.CleanData"/> <queryString language="SQL"> <![CDATA[ SELECT id, name, occupation, salary from users ]]> </queryString> <field name="id" class="java.lang.Integer"/> <field name="name"/> <field name="occupation"/> <field name="salary" class="java.lang.Integer" /> <variable name="sumsal" class="java.lang.Integer" calculation="Sum"> <variableExpression><![CDATA[$F{salary}]]></variableExpression> </variable> <title> <band height="60"> <staticText> <reportElement x="0" y="0" width="595" height="35"/> <textElement textAlignment="Center"/> <text><![CDATA[Users]]></text> </staticText> </band> </title> <detail> <band height="30"> <textField> <reportElement x="0" y="0" width="25" height="25"/> <textFieldExpression class="java.lang.Integer"> <![CDATA[$F{id}]]> </textFieldExpression> </textField> <textField> <reportElement x="30" y="0" width="100" height="25"/> <textFieldExpression> <![CDATA[$F{name}]]> </textFieldExpression> </textField> <textField> <reportElement x="140" y="0" width="70" height="25"/> <textFieldExpression> <![CDATA[ CleanData.removeNull($F{occupation}, 'N/A') ]]> </textFieldExpression> </textField> <textField> <reportElement x="220" y="0" width="70" height="25"/> <textElement textAlignment="Right"/> <textFieldExpression> <![CDATA[ CleanData.removeNull($F{salary}, 'N/A') ]]> </textFieldExpression> </textField> </band> </detail> <summary> <band height="25"> <textField> <reportElement x="220" y="0" width="70" height="25"/> <textElement textAlignment="Right"> <font isBold = "true"/> </textElement> <textFieldExpression><![CDATA[$V{sumsal}]]></textFieldExpression> </textField> </band> </summary> </jasperReport>
In this report, we use the external CleanData.removeNull
method.
<import value="com.zetcode.CleanData"/>
We import the class to the report.
<textField> <reportElement x="140" y="0" width="70" height="25"/> <textFieldExpression> <![CDATA[ CleanData.removeNull($F{occupation}, 'N/A') ]]> </textFieldExpression> </textField>
We pass the CleanData.removeNull
the $F{occupation}
value and the optional string to replace the potential null value.
In this article we demonstrated how to replace null values with empty strings or more descriptive messages.