Barcodes in JasperReports
|
This content was generated with the assistance of AI and should be verified against the official documentation before being relied on in production. The reference material consulted while preparing these pages is listed in the section bibliography. |
Baseline date: 2026-10-09. A report that prints shelf labels, delivery notes or invoices usually needs a symbol that a
scanner can read: a Code 128 with the SKU, an EAN-13 with the ISBN, a QR code with a URL. JasperReports 7.0.8 has two
ways to put one in a band. The first is a built-in report component, with kind="component" and a child element that
names the symbol type: the Barcode4J component, which covers the usual linear and two-dimensional symbologies, and the
older Barbecue component. The second is an ordinary image element whose expression returns a picture that the
application drew itself, for example with ZXing. This page shows all of them in the Bookshelf Billing scenario, with
the v7 JRXML syntax, what each one can and cannot do, how to size a symbol inside a band, and which one to choose today.
The examples were compiled and run with Java 21 and JasperReports 7.0.8 in a plain Maven project. Each resulting PDF was rendered with PDFBox 3.0.8 and scanned with ZXing 3.5.4, so a statement that a symbol decodes means that it did. Where a symbol was only rendered and looked at, the text says so. The theory of the symbologies themselves (module, quiet zone, check digits, error correction) is in Barcodes & QR Codes: Fundamentals, and the same symbols drawn with iText are in Barcodes with iText & ZXing. The template format is the JasperReports 7 JRXML described in JRXML Report Design. Tax-regulated QR codes, such as the one on a Spanish invoice, have their own rules and are in Regulated QR Codes.
Which approach to choose
Three options exist, and the choice is mostly about maintenance and about what the symbol must contain.
-
Barcode4J component (
jasperreports-barcode4j). Maintained as part of JasperReports itself, so the integration keeps working with each release, but the encoder library underneath (Barcode4J 2.1) dates from 2012 and is dormant. The QR code is the exception: it is encoded by ZXing, not by Barcode4J. It is the right choice for labels and for standard linear symbols, because everything is declared in the template and nothing needs Java code. -
Barbecue component (
jasperreports-barbecue). It wraps Barbecue 1.5-beta1, which was abandoned upstream. It exists in 7.0.8 for old templates. New templates should not use it, because Barcode4J covers the same symbologies and more. -
ZXing as an image expression or renderer. ZXing 3.5.4 is current and actively maintained. The cost is a few lines of Java and the loss of a template that is self-contained. It is the right choice for a QR code that needs a specific version, a mask, a character set, a logo in the middle or the very latest bug fixes, and for any case where the application already builds the payload in Java, such as the regulated QR code of an invoice.
Whatever is chosen, the library licences are permissive for this use: JasperReports 7 is distributed under the LGPL, Barcode4J and ZXing under the Apache License 2.0. This is unlike iText, which is AGPL or commercial, so a report that only needs a barcode has no licensing reason to move to another library.
Maven setup
The Barcode4J component is a separate artifact from the engine and is not pulled in by jasperreports. Add it next to
the PDF exporter, the fonts and the expression compiler used by the other pages of this section. ZXing is declared
explicitly, even for the component, for a reason explained below.
<properties>
<maven.compiler.release>21</maven.compiler.release>
<jasperreports.version>7.0.8</jasperreports.version>
<zxing.version>3.5.4</zxing.version>
</properties>
<dependencies>
<dependency>
<groupId>net.sf.jasperreports</groupId>
<artifactId>jasperreports</artifactId>
<version>${jasperreports.version}</version>
</dependency>
<dependency>
<groupId>net.sf.jasperreports</groupId>
<artifactId>jasperreports-barcode4j</artifactId>
<version>${jasperreports.version}</version>
</dependency>
<dependency>
<groupId>net.sf.jasperreports</groupId>
<artifactId>jasperreports-pdf</artifactId>
<version>${jasperreports.version}</version>
</dependency>
<dependency>
<groupId>net.sf.jasperreports</groupId>
<artifactId>jasperreports-fonts</artifactId>
<version>${jasperreports.version}</version>
</dependency>
<dependency>
<groupId>net.sf.jasperreports</groupId>
<artifactId>jasperreports-jdt</artifactId>
<version>${jasperreports.version}</version>
</dependency>
<dependency>
<groupId>com.google.zxing</groupId>
<artifactId>core</artifactId>
<version>${zxing.version}</version>
</dependency>
<dependency>
<groupId>com.google.zxing</groupId>
<artifactId>javase</artifactId>
<version>${zxing.version}</version>
</dependency>
</dependencies>
What the dependency tree showed in the run: jasperreports-barcode4j 7.0.8 brings net.sf.barcode4j:barcode4j 2.1 and
declares com.google.zxing:core 3.4.0 as a compile dependency. With ZXing 3.5.4 declared in the project, Maven’s
nearest-wins rule resolved core to 3.5.4, and the QR code of the component rendered and decoded with it. Declaring
the version that the application wants, rather than relying on the transitive one, also keeps the component and the
custom ZXing code of the later sections on the same encoder. javase is only needed by the image-expression alternative,
for MatrixToImageWriter.
The Maven coordinates and versions are documented on Maven Central. The rest of the project, including the Spring Boot setup, is in Getting Started with Spring Boot.
The Barcode4J component in v7 JRXML
In JasperReports 6 a barcode was a namespaced element in the jr component namespace, inside a
componentElement, and the template was validated against a schema. Version 7
replaced the XML binding with Jackson, and the template has no namespace any more. A component is an element with
kind="component", a position and a size, and it has one child, component, whose kind attribute names the
component. For Barcode4J the names have the form barcode4j: followed by the symbology, and the value to encode is
given by a codeExpression child. A v6 template that contains barcodes cannot be loaded by 7.0.8 and has to be
converted with Jaspersoft Studio 7, which is finding O15 of the section’s list of outdated points. A quick way to
confirm that a component kind is known is to misspell it: the engine reports the known type ids, which in the
run were barcode4j:Codabar, barcode4j:Code128, barcode4j:Code39, barcode4j:DataMatrix, barcode4j:EAN128,
barcode4j:EAN13, barcode4j:EAN8, barcode4j:Interleaved2Of5, barcode4j:PDF417, barcode4j:POSTNET,
barcode4j:QRCode, barcode4j:RoyalMailCustomer, barcode4j:UPCA, barcode4j:UPCE and
barcode4j:USPSIntelligentMail.
The following template is the shelf-label report of the Bookshelf store. Each label has the title of the book, a Code
128 with the internal SKU, an EAN-13 with the ISBN and a QR code that opens the product page. The ISBNs and SKUs are
invented sample values, and shop.example.com is a reserved example domain.
<jasperReport name="book-labels" language="java" pageWidth="595" pageHeight="842"
columnWidth="515" leftMargin="40" rightMargin="40" topMargin="40" bottomMargin="40">
<field name="sku" class="java.lang.String"/>
<field name="isbn13" class="java.lang.String"/>
<field name="title" class="java.lang.String"/>
<title height="30">
<element kind="staticText" x="0" y="0" width="515" height="24" fontSize="16" bold="true">
<text><![CDATA[Bookshelf shelf labels]]></text>
</element>
</title>
<detail>
<band height="70">
<element kind="textField" x="0" y="0" width="200" height="16" bold="true">
<expression><![CDATA[$F{title}]]></expression>
</element>
<element kind="component" x="0" y="18" width="200" height="45">
<component kind="barcode4j:Code128" textPosition="bottom" moduleWidth="0.4">
<codeExpression><![CDATA[$F{sku}]]></codeExpression>
</component>
</element>
<element kind="component" x="230" y="4" width="130" height="60">
<component kind="barcode4j:EAN13" textPosition="bottom">
<codeExpression><![CDATA[$F{isbn13}]]></codeExpression>
</component>
</element>
<element kind="component" x="400" y="4" width="60" height="60">
<component kind="barcode4j:QRCode" errorCorrectionLevel="M" margin="0">
<codeExpression><![CDATA["https://shop.example.com/books/" + $F{sku}]]></codeExpression>
</component>
</element>
</band>
</detail>
</jasperReport>
The template is compiled, filled and exported like any other. The record below is the data row, with the getters that the bean data source reads. The class is a plain, runnable main method.
package bookshelf;
import java.io.InputStream;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.HashMap;
import java.util.List;
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;
import net.sf.jasperreports.engine.data.JRBeanCollectionDataSource;
public class BarcodeReport {
public record Label(String sku, String isbn13, String title) {
public String getSku() { return sku; }
public String getIsbn13() { return isbn13; }
public String getTitle() { return title; }
}
public static void main(String[] args) throws Exception {
JasperReport report;
try (InputStream in = BarcodeReport.class.getResourceAsStream("/reports/labels.jrxml")) {
report = JasperCompileManager.compileReport(in);
}
List<Label> labels = List.of(
new Label("BK-000123", "9780306406157", "Distributed Systems Primer"),
new Label("BK-000124", "9780131103627", "Practical Algebra"));
JasperPrint print = JasperFillManager.fillReport(
report, new HashMap<String, Object>(), new JRBeanCollectionDataSource(labels));
Files.createDirectories(Path.of("target/out"));
JasperExportManager.exportReportToPdfFile(print, "target/out/labels.pdf");
}
}
In the run, the PDF had one page, and a ZXing scan of the rendered page found the two Code 128 symbols with the two SKUs, the two EAN-13 symbols with the two ISBNs and the two QR codes with the two URLs. The pieces that the page relies on are documented in the Barcode4J sample and the engine’s generic compile and export calls in JasperReports Architecture & Lifecycle.
Symbologies and their attributes
The component classes of 7.0.8 define the attributes below. All the component kinds share the codeExpression child
and the evaluation attributes of every component (evaluationTime, and evaluationGroup when the time is Group),
which matter when the code depends on a variable such as a report total that is only known at the end of the report. All
linear and 2D kinds except the QR code also share the Barcode4J attributes orientation (up, left, down, right),
moduleWidth, textPosition (none, bottom, top), quietZone, verticalQuietZone and a patternExpression
child, which formats the human-readable text.
| Component kind | Symbology and typical use | Attributes of its own |
|---|---|---|
|
Code 128, compact alphanumeric labels and shipping references. Chosen for the SKU. |
none beyond the shared ones |
|
Code 39, older industrial and library labels, upper-case letters, digits and a few symbols. |
|
|
EAN-13 and EAN-8. ISBN-13 is an EAN-13 whose prefix is 978 or 979. |
|
|
UPC-A (12 digits) and UPC-E (compressed), North American retail. |
|
|
Codabar, Interleaved 2 of 5 and GS1-128 (EAN-128, with application identifiers). |
|
|
Data Matrix, compact 2D symbol for small parts. |
|
|
PDF417, stacked linear 2D symbol, used on boarding passes and some official documents. |
|
|
Four-state postal codes (the USPS ones are US postal symbologies). |
|
|
QR code, encoded and rendered with ZXing. |
|
The table is read from the compiled classes of the 7.0.8 artifact, so attribute names are the ones that Jackson binds
in a v7 template. Values such as the checksumMode strings (auto, check, add, ignore) are those of
Barcode4J. The JasperReports engine’s own documentation of the components is the
Barcode4J sample page, and the
upstream project describes every symbology in the
Barcode4J documentation and on its
SourceForge project page. The QR code has been rendered with ZXing since
JasperReports 6.0.2, before which the component had no QR code.
A second run exercised the other kinds in one template, one element per symbol, with the attributes in the table where relevant. The Code 128, Code 39, EAN-8 and UPC-A symbols decoded with the expected values. The Data Matrix, PDF417, POSTNET and USPS Intelligent Mail symbols rendered and were checked by eye on the page image, but were not scanned, so nothing here claims they are readable. The POSTNET and USPS symbols are US postal formats. The USPS Intelligent Mail symbol expects a 20, 25, 29 or 31 digit string, and the engine accepted a 31 digit sample value.
Check digits and invalid values
A barcode that is wrong is worse than no barcode, so the behaviour on bad input is worth knowing. In the run:
-
An EAN-13 value of twelve digits was accepted and the symbol decoded with the thirteenth digit, the check digit, added by the encoder.
-
An EAN-13 with thirteen digits and a wrong last digit stopped the fill with a
JRRuntimeExceptionwhose cause wasIllegalArgumentException: Checksum is bad (8). Expected: 7. A value with a letter stopped it as well, withInvalid characters found. Valid are 0-9 only. The whole report fails, not just the label, so validate the code in Java before the data reaches the template if one bad row must not stop a batch. -
A
nullcode expression produced an empty area and no error. The page rendered and no symbol was found on it. -
An empty string for the QR code produced a valid QR code that decodes to an empty text. Use a
printWhenExpressionon the element, or returnnullfor blank values in the expression, if an empty symbol must not be printed.
The checksumMode attribute decides what happens with the check digit for the symbologies that have one. With auto
the encoder uses the default of the symbology, with check it verifies a supplied digit and with add it computes one.
Sizing a symbol in a band
A barcode component is drawn by Barcode4J at a size that comes from the symbol and from moduleWidth, then placed in the
element rectangle. The element’s width and height therefore do not stretch the bars. This is the main source of
surprises, so the points below are the result of rendering the same Code 128 in elements of different sizes:
-
The symbol is not stretched to the element. A Code 128 of nine characters in an element 300 points wide was drawn at its natural size, about 55 points wide, at the left of the element, and a larger box did not make the bars wider. The width comes from the number of characters and from
moduleWidth. The unit ofmoduleWidthand its exact scaling were not worked out in the run (values of 0.5 and the default gave symbols of similar width), so tune it by trial. -
A module that is too small is unreadable. A
moduleWidthof 0.1 rendered as a grey smear about 11 points wide on the page image. The minimum module depends on the symbology’s standard, the printer resolution and the scanner, so test with the real printer and scanner before fixing a label design. -
Height is the element height minus the text. With
textPosition="bottom"the human-readable text takes part of the height, and withnoneall of it goes to the bars, so make the element high enough for the scanner in use. -
Quiet zone.
quietZoneandverticalQuietZoneare the white margins in modules, and the QRmarginis in modules. The page itself is white, so a symbol placed on white paper has a quiet zone as long as no other element is within it. Never put a coloured background, a line or a text field in the margin of the symbol. The QR code of the labels above usedmargin="0"and still decoded, because the surrounding area was empty. -
Orientation.
orientation="left"rotates the symbol by 90 degrees to the left. The element rectangle is not rotated with it, so the element must be tall instead of wide, and the symbol was drawn across the full width of a wide element in the run. Allow for it when laying out a vertical label. -
Two-dimensional symbols. A QR code and a Data Matrix are square. Give them a square element. In a non-square one the symbol follows the smaller side, so extra space is empty. A PDF417 in an element of 55 points of height was squashed into a dense block. Set
minColumns,maxColumnsandwidthToHeightRatioso that the aspect ratio of the symbol matches the element.
The overall rule for a band is to size the symbol first, using moduleWidth and the number of characters, then set the element rectangle to that size plus the quiet zone, and finally make the band high enough for the element. For a
fixed grid of labels, such as sheets of stickers, a detail band of fixed height, as described in
JRXML Report Design, is simpler than a stretching band.
Vector or raster: the image producer
Barcode4J does not draw into the PDF directly. An image producer turns the symbol into an image, and the default is the
SVG producer. The effect on a PDF is visible: in the run, the PDF of the label report had no image XObject on the page,
so the bars are vector paths, sharp at any zoom, and the file is small. The raster producer is selected by a property,
which can be set globally in jasperreports.properties, per report as a property element, or on a single element:
<jasperReport name="size" language="java" pageWidth="595" pageHeight="842">
<property name="net.sf.jasperreports.components.barcode4j.image.producer" value="image"/>
...
</jasperReport>
With the value image the same template produced one raster image per symbol: three images of between 96 and 327
pixels in width and 167 in height for three Code 128 elements, at the default resolution. The resolution is set by
net.sf.jasperreports.components.barcode4j.image.resolution (300 by default), and the properties
...image.gray and ...image.antiAlias (both true by default) control the colour model and the smoothing. Anti-aliasing
a bar code is harmful for a scanner, because the edge of a bar becomes grey. Prefer the default SVG producer for PDF
output, and use the raster producer only for an exporter that cannot draw vectors. The QR code has its own producer
property, net.sf.jasperreports.components.barcode4j.qrcode.producer.{alias}, and the character set of its payload is
net.sf.jasperreports.components.qrcode.character.encoding, whose default in 7.0.8 is UTF-8. All of them are listed in
the configuration reference.
The Barbecue component
The jasperreports-barbecue artifact wraps Barbecue 1.5-beta1, a project that has been abandoned upstream. Its
coordinates are net.sf.jasperreports:jasperreports-barbecue with the same version as the engine, and it works in
7.0.8, but with a different, older template structure. In v7 JRXML its kind has no symbology suffix: the symbology is the
type attribute.
<element kind="component" x="0" y="0" width="200" height="60">
<component kind="barbecue" type="Code128" drawText="true" barWidth="1" barHeight="40">
<codeExpression><![CDATA[$F{sku}]]></codeExpression>
</component>
</element>
With jasperreports-barbecue on the classpath the template compiled and filled, the PDF had a vector Code 128 and
ZXing decoded it. The attribute names come from the component class, which also has checksumRequired, rotation
and an applicationIdentifierExpression for GS1-128. Two other variants, barbecue:Code128 and barbecue:barbecue, were
refused with the unresolved type id error shown above. The component’s types are those of the Barbecue library (Code 128 A,
B and C, Code 39, Codabar, EAN-13, UPC-A, 2 of 7 and others), and it has no QR code, no Data Matrix and no PDF417. Because
the upstream project is not maintained, the page recommends it only for a template that already uses it. The upstream
projects are on SourceForge, and the engine’s
Barbecue sample shows the component.
A maintained alternative: ZXing as an image expression
The image element prints what its expression returns, and the expression may return a java.awt.Image, a path or URL
string, an input stream, or a net.sf.jasperreports.renderers.Renderable. A static helper that draws a QR code with
ZXing 3.5.4 is therefore enough, and the template stays free of any component. This is the pattern for the QR code of an
invoice, where the payload is built in Java, and also for the formats the Barcode4J component lacks, such as the
Aztec code, which ZXing writes as well.
package bookshelf;
import java.awt.image.BufferedImage;
import java.util.Map;
import com.google.zxing.BarcodeFormat;
import com.google.zxing.EncodeHintType;
import com.google.zxing.WriterException;
import com.google.zxing.client.j2se.MatrixToImageWriter;
import com.google.zxing.common.BitMatrix;
import com.google.zxing.qrcode.QRCodeWriter;
import com.google.zxing.qrcode.decoder.ErrorCorrectionLevel;
/** Static helpers called from JRXML expressions. */
public final class ZxingImages {
private ZxingImages() {
}
public static BufferedImage qr(String text, int sizePx) throws WriterException {
Map<EncodeHintType, Object> hints = Map.of(
EncodeHintType.ERROR_CORRECTION, ErrorCorrectionLevel.M,
EncodeHintType.MARGIN, 0,
EncodeHintType.CHARACTER_SET, "UTF-8");
BitMatrix matrix = new QRCodeWriter().encode(text, BarcodeFormat.QR_CODE, sizePx, sizePx, hints);
return MatrixToImageWriter.toBufferedImage(matrix);
}
}
The class is made visible to the expressions with an import element, whose content is the class name in v7 JRXML
(an import element with a value attribute, the form of the v6 import declaration, is not read: the compiler
reported Syntax error on token "import" and the template did not compile). The image element declares the
expression class so that the compiler knows the type:
<jasperReport name="zxing-qr" language="java" pageWidth="595" pageHeight="842"
columnWidth="515" leftMargin="40" rightMargin="40" topMargin="40" bottomMargin="40">
<import>bookshelf.ZxingImages</import>
<field name="sku" class="java.lang.String"/>
<field name="title" class="java.lang.String"/>
<detail>
<band height="90">
<element kind="textField" x="0" y="0" width="200" height="16" bold="true">
<expression><![CDATA[$F{title}]]></expression>
</element>
<element kind="image" x="230" y="4" width="80" height="80" scaleImage="FillFrame" onErrorType="Error">
<expression class="java.awt.Image"><![CDATA[ZxingImages.qr("https://shop.example.com/books/" + $F{sku}, 400)]]></expression>
</element>
</band>
</detail>
</jasperReport>
Three details matter. The size in pixels is the resolution of the bitmap, not the printed size: 400 pixels in an 80 point
frame is a bit more than 360 dpi, which is plenty. scaleImage="FillFrame" stretches the bitmap to the frame, and since
the matrix was generated square and without margin, a square frame keeps the modules square. And the expression runs once
per row, in the fill, so a heavy encoder should not be used for thousands of rows without a cache.
In the run, the PDF page contained one 400 by 400 raster image per row, the exporter embedded the bitmap as it was, and the QR codes decoded with the SKU URLs. Drawn at a larger size the edges of such a bitmap blur in a viewer. The next section avoids it.
A vector QR code with a Graphics2D renderer
A Renderable is the engine’s abstraction of something that can be drawn into an image slot, and the
Graphics2DRenderable interface is the form that draws into a Java2D Graphics2D at the rectangle that the layout
gives it. The PDF exporter draws such a renderable as vector graphics. A renderer that draws every dark module of a QR code
as a rectangle gives a QR code that is sharp at any zoom and costs no bitmap. ZXing’s Encoder is used directly to get
the module matrix without the quiet zone.
package bookshelf;
import java.awt.Color;
import java.awt.Graphics2D;
import java.awt.geom.Path2D;
import java.awt.geom.Rectangle2D;
import java.util.Map;
import com.google.zxing.EncodeHintType;
import com.google.zxing.qrcode.decoder.ErrorCorrectionLevel;
import com.google.zxing.qrcode.encoder.ByteMatrix;
import com.google.zxing.qrcode.encoder.Encoder;
import net.sf.jasperreports.engine.JRException;
import net.sf.jasperreports.engine.JasperReportsContext;
import net.sf.jasperreports.renderers.AbstractRenderToImageAwareRenderer;
import net.sf.jasperreports.renderers.Graphics2DRenderable;
/** Vector QR code: every dark module is drawn as a rectangle, so the PDF stays sharp at any zoom. */
public class QrRenderer extends AbstractRenderToImageAwareRenderer implements Graphics2DRenderable {
private static final long serialVersionUID = 1L;
private final ByteMatrix matrix;
public QrRenderer(String text) throws Exception {
this.matrix = Encoder.encode(text, ErrorCorrectionLevel.M,
Map.of(EncodeHintType.CHARACTER_SET, "UTF-8")).getMatrix();
}
@Override
public void render(JasperReportsContext context, Graphics2D g, Rectangle2D rectangle) throws JRException {
double module = Math.min(rectangle.getWidth(), rectangle.getHeight()) / matrix.getWidth();
Path2D.Double dark = new Path2D.Double(Path2D.WIND_NON_ZERO);
for (int y = 0; y < matrix.getHeight(); y++) {
for (int x = 0; x < matrix.getWidth(); x++) {
if (matrix.get(x, y) == 1) {
dark.append(new Rectangle2D.Double(
rectangle.getX() + x * module, rectangle.getY() + y * module, module, module), false);
}
}
}
g.setColor(Color.BLACK);
g.fill(dark);
}
}
The base class of the renderer is AbstractRenderToImageAwareRenderer in 7.0.8. A source that names
AbstractRenderToImageAwareRenderable is from a version before 7 and does not compile. The template places the renderer with
an expression of the class net.sf.jasperreports.renderers.Renderable:
<import>bookshelf.QrRenderer</import>
...
<element kind="image" x="400" y="4" width="80" height="80" scaleImage="RetainShape" onErrorType="Error">
<expression class="net.sf.jasperreports.renderers.Renderable"><![CDATA[new QrRenderer("https://shop.example.com/books/" + $F{sku})]]></expression>
</element>
A first version of the renderer filled one rectangle per module, one fill call each. The page rendered, and it looked
right, but ZXing could not decode the QR code, because the anti-aliased edges of adjacent rectangles left hairline
seams between modules at 300 dpi. Collecting all the modules into one Path2D and filling it once, as in the listing,
made the symbol decode. This is worth remembering for any renderer that draws a symbol from many shapes: draw the
dark area as one path. With that change, the PDF page of the run contained no image XObject for the renderer, only the
bitmap of the previous element, and the QR code decoded with the SKU URL.
The matrix returned by Encoder has no quiet zone, so the element must be surrounded by white space, at least four
modules wide, as the QR standard requires. The listing is the minimal version. To add a logo, reduce the
symbol with level H, draw the logo in the centre area and verify with a scanner that the result still decodes. The
background, a custom foreground colour or rounded modules are all one-line changes in render, but contrast between
modules and background is what a scanner needs, so a dark module colour on a light background is the safe choice.
The API of the interface is in the
JasperReports API
documentation, and the ZXing library on the ZXing GitHub project with the
API documentation.
Data to put in the symbol
The component and the image expression solve the drawing. What goes into the symbol is a separate decision.
-
A shelf label needs a short, stable identifier such as the SKU. The scanner finds the record in the database, so the symbol should not repeat the title or the price.
-
A product page link is a URL. A longer payload needs a higher QR version, a larger symbol or more modules, and a payload of about 50 characters is comfortably readable at 20 millimetres.
-
An invoice QR code carries a fixed structure that an authority defines. Its payload, error-correction level, size and position are rules, not choices, and are described in Regulated QR Codes. Build the payload in Java, with a unit test that parses it back, and pass the string to the template as a parameter.
-
Do not put personal data in a QR code on a document that may be photographed or forwarded. The symbol is readable by anybody with a phone, and a QR code cannot be revoked like a link.
A report that has a URL in the symbol often also prints it as text, for people who cannot scan it. A textField with
hyperlinkType="Reference" also makes the printed text a clickable link in the PDF, as described in
Hyperlinks, Bookmarks & Report Books.
Spring Boot service notes
In the Spring Boot service of the scenario, the template is compiled once at start-up or at build time, as in Spring Boot Integration, and filled per request. Three consequences for barcodes follow.
-
The
jasperreports-barcode4jartifact must be on the runtime classpath. If it is not, compilation fails with Jackson’sCould not resolve type iderror and a list of known ids that does not contain thebarcode4j:kinds. The message does not name the missing artifact. -
An import in the template (
<import>bookshelf.ZxingImages</import>) is resolved against the application’s classpath, so a helper class can be a Spring-managed class only if the method called is static, or if the instance is passed as a report parameter. A static helper with no state is the simplest. -
Because expressions are code, the usual care about untrusted templates applies, as in Security Hardening. A helper that encodes whatever string the template gives it does not add a risk, but one that fetches a URL, reads a file or logs its argument does.
When the labels are only a part of a larger document, the PDF produced can be post-processed. A filled form or a signature is added after the export, as in Signing with iText. For a signed document, the symbol is part of the content that is signed, so it must be drawn before the signature, never after.
Outdated points to avoid
Older books and tutorials on JasperReports describe barcodes in ways that no longer apply to 7.0.8.
-
A barcode as a
componentElementin thejrnamespace, validated against the DTD or an XSD, is the v6 format. A JasperReports 7 template has no namespace and useskind="component"with acomponentchild (finding O15). Templates in the old format must be converted with Jaspersoft Studio 7, because 7.0.8 does not load them. -
Older recipes draw a barcode with a barcode font, a scriptlet or the Barbecue classes in an image expression. The Barcode4J component or ZXing make these unnecessary, and the Barbecue library has been abandoned upstream.
-
Examples written for Java 1.4 to 8 use raw types and anonymous classes. The examples here are Java 21 (finding O28), with a record for the data and the Jakarta-era dependencies of JasperReports 7.
-
Advice to render a barcode as a bitmap at low resolution to save space is obsolete: the default SVG producer gives a small, sharp vector symbol in the PDF.
Limits of this page
The Code 128, Code 39, EAN-8, EAN-13, UPC-A and QR symbols, the Barbecue Code 128 and both ZXing alternatives were scanned back from the rendered PDF. The Data Matrix, PDF417, POSTNET and USPS Intelligent Mail symbols were rendered and inspected visually only. The scan was done on the PDF rendered at 300 dpi on a screen, which says nothing about a thermal printer, a laser printer, a label’s material or a particular scanner. Verify each symbology in the real printing chain before a label design is approved. The product of this page is a template that is correct, not a guarantee that a given symbol is readable in a warehouse.
References
-
Barcodes & QR Codes: Fundamentals on this site
-
Barcodes with iText & ZXing on this site
-
Regulated QR Codes on this site
-
JRXML Report Design on this site
-
JasperReports Architecture & Lifecycle on this site
-
Spring Boot Integration on this site
-
Security Hardening on this site
-
Getting Started with Spring Boot on this site