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.