JasperReports conditional data/connection source

Author
Damian
Terlecki
6 minutes read
Misc

JasperReports is an open-source tool for generating reports in many formats like PDF, Excel, HTML, and many others. It can be used as a Java library or a standalone server and comes with a good editor (TIBCO Jaspersoft® Studio) for preparing report templates. You can provide input through various means, but in general, there are three types of input sources as shown in methods of net.sf.jasperreports.engine.JasperFillManager:

  • parameters that can be passed from the code or entered by a user in the editor;
  • net.sf.jasperreports.engine.JRDataSource with implementation for bean collections;
  • java.sql.Connection that provides data from a database.

Data source in subDataset

You can interchange the data and connection sources. Yet, it is somewhat harder to achieve the same thing at the level of sub-datasets that display a dynamic number of sub-records. The datasetRun element of the report template used to configure this accepts either the connectionExpression or dataSourceExpression, but not both.

<element name="datasetRun">
    <annotation>
        <documentation>Subdataset instantiation information for a chart/crosstab dataset.</documentation>
    </annotation>
    <complexType>
        <sequence>
            <!--...-->
            <choice minOccurs="0" maxOccurs="1">
                <element ref="jr:connectionExpression"/>
                <element ref="jr:dataSourceExpression"/>
            </choice>
            <!--...-->
        </sequence>
        <attribute name="subDataset" type="string" use="required">
            <annotation>
                <documentation>The name of the <elem>subdataset</elem> to instantiate.</documentation>
            </annotation>
        </attribute>
        <!--...-->
    </complexType>
</element>

Sometimes you might want to use an inlined and database-independent data source. This is useful when designing the report without the real data, as well as to prepare placeholders. Other times you might want to just dynamically change between sources if your application happens to have already fetched the necessary data.

There is no clear way to specify a condition that dynamically chooses one source over the other: This schema constraint is reflected in the configuration options visible in the editor for a table element:

JasperReports Table Dataset

Conditional data/connection source

To bypass the <choice minOccurs="0" maxOccurs="1"> constraint, do not define the expressions at all in the JRXML. Instead, pass either the REPORT_DATA_SOURCE or REPORT_CONNECTION parameter to the sub-dataset. This way you can achieve a conditional data/connection source:

<!--...-->
<datasetRun subDataset="myDataSet" uuid="d015cfdd-7c38-4915-8fb7-e493eb381ec4">
    <datasetParameter name="REPORT_DATA_SOURCE">
        <datasetParameterExpression><![CDATA[
        $P{usePlaceholderDataSource} 
            ? new net.sf.jasperreports.engine.data.ListOfArrayDataSource(
                Arrays.asList(new String[]{"John", "Doe"}, new String[]{"Mary", "Sue"}),
                new String[]{"firstName", "lastName"})
            : null
        ]]></datasetParameterExpression>
    </datasetParameter>
    <datasetParameter name="REPORT_CONNECTION">
        <datasetParameterExpression><![CDATA[
        $P{usePlaceholderDataSource} 
            ? null
            : $P{REPORT_CONNECTION}
        ]]></datasetParameterExpression>
    </datasetParameter>
</datasetRun>
<!--...-->

When the usePlaceholderDataSource flag is on, the report will be filled with inlined placeholder data. Otherwise, a connection from the master report will be used to fetch real data. I've used this with JasperReports 6.20.0, but feel free to try this even with some older versions.