JasperReports

A Quarkus extension that lets you utilize JasperReports. JasperReports is an open source Java reporting tool that can write to a variety of targets, such as: screen, a printer, into PDF, HTML, Microsoft Excel, RTF, ODT, comma-separated values (CSV), XSL, or XML files.

Installation

If you want to use this extension, you need to add the io.quarkiverse.jasperreports:quarkus-jasperreports extension first to your build file.

For instance, with Maven, add the following dependency to your POM file:

<dependency>
    <groupId>io.quarkiverse.jasperreports</groupId>
    <artifactId>quarkus-jasperreports</artifactId>
    <version>1.0.3</version>
</dependency>

Compiling Reports

JasperReports advises against compiling .jrxml reports on the fly. However, if necessary, this can only be done in JVM mode, as native mode does not support Java compilation due to the absence of a Java compiler and the required classes for compilation. The recommended best practice is to use precompiled .jasper files.

This extension provides built-in functionality to assist with this. If you place your .jrxml files in the quarkus.jasperreports.build.source directory, they will be automatically compiled into .jasper files in the quarkus.jasperreports.build.dest directory. In DEV mode, it will monitor changes in the .jrxml files and recompile them, enhancing developer productivity and joy!

Database Datasource

When utilizing an Agroal Datasource to generate your report, ensure it is not within an active transaction. JasperReports employs threads for sub-reports and various features, and a connection cannot be passed across thread boundaries while in a transaction. Failing to do so will result in the following error: Enlisted connection used without active transaction.

Caused by: java.sql.SQLException: Enlisted connection used without active transaction
2024-07-22T21:24:13.599110173Z  at io.agroal.pool.ConnectionHandler.verifyEnlistment(ConnectionHandler.java:398)
2024-07-22T21:24:13.599149982Z  at io.agroal.pool.wrapper.ConnectionWrapper.getMetaData(ConnectionWrapper.java:452)
2024-07-22T21:24:13.599212173Z  at net.sf.jasperreports.engine.query.OracleProcedureCallHandler.isOracle(OracleProcedureCallHandler.java:72)
2024-07-22T21:24:13.599341106Z  at net.sf.jasperreports.engine.query.JRJdbcQueryExecuter.isProcedureCall(JRJdbcQueryExecuter.java:566)
2024-07-22T21:24:13.599481640Z  at net.sf.jasperreports.engine.query.JRJdbcQueryExecuter.createStatement(JRJdbcQueryExecuter.java:389)
In your service you must use @Transactional(Transactional.TxType.NEVER) above the method that is filling your report.
@Inject
DataSource datasource;

@Transactional(Transactional.TxType.NEVER)
public byte[] text() throws JRException, SQLException {
    JasperPrint jasperPrint = null;
     try (final Connection connection = datasource.getConnection()) {
         params.put(JRParameter.REPORT_CONNECTION, connection);

         jasperPrint = JRFiller.fill(DefaultJasperReportsContext.getInstance(), SimpleJasperReportSource.from(mainReport, null, new SimpleRepositoryResourceContext()), params);
     }
    final JRTextExporter exporter = new JRTextExporter();
    exporter.setExporterInput(new SimpleExporterInput(jasperPrint));
    ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
    exporter.setExporterOutput(new SimpleWriterExporterOutput(outputStream));
    exporter.exportReport();
    return outputStream.toByteArray();
}

Read-Only Streaming Service

This extension offers an injectable JasperReports repository capable of managing all the resources required for a report, including referenced sub-reports. Just inject the ReadOnlyStreamingService repository and use it with the fill manager to generate the report.

    @Inject
    ReadOnlyStreamingService jasperService;

    public JasperPrint fill() throws JRException {
        Map<String, Object> params = new HashMap<>();
        return JasperFillManager.getInstance(jasperService.getContext()).fillFromRepo("MyReport.jasper", params);
    }

Native Container

When building native images in Docker using the standard Quarkus Docker configuration files some additional features need to be installed to support fonts. Specifically font information is not included in Red Hat’s ubi-minimal images. To install it simply add these lines to your DockerFile.native file:

FROM registry.access.redhat.com/ubi8/ubi-minimal:8.9

######################### Set up environment for POI ##########################
RUN microdnf update && microdnf install freetype fontconfig && microdnf clean all
######################### Set up environment for POI ##########################

WORKDIR /work/
RUN chown 1001 /work \
    && chmod "g+rwX" /work \
    && chown 1001:root /work
# Shared objects to be dynamically loaded at runtime as needed,
COPY --chown=1001:root target/*.properties target/*.so /work/
COPY --chown=1001:root target/*-runner /work/application
# Permissions fix for Windows
RUN chmod "ugo+x" /work/application
EXPOSE 8080
USER 1001

CMD ["./application", "-Dquarkus.http.host=0.0.0.0"]
Make sure .dockerignore does not exclude .so files!

Extension Configuration Reference

Configuration property fixed at build time - All other configuration properties are overridable at runtime

Configuration property

Type

Default

Enable building all report files.

Environment variable: QUARKUS_JASPERREPORTS_BUILD_ENABLE

boolean

true

The path where all source .jrxml and .jrtx files are located.

Environment variable: QUARKUS_JASPERREPORTS_BUILD_SOURCE

path

src/main/jasperreports

The path where compiled reports are located next to compiled classes.

Environment variable: QUARKUS_JASPERREPORTS_BUILD_DESTINATION

path

jasperreports