How to pass main report data source to subreport (JasperReports)?
Yes, you need to be careful about how to pass a data source. With a SQL connection, you can just pass a Connection Expression like $P{REPORT_CONNECTION}
. Then the subreport has its own SQL query.
In your case you want to pass the actual data. Depending on the details, it might be as simple as just defining a Parameter Map Expression like $P{REPORT_PARAMETERS_MAP}
. It's on a different tab in that same window where you set the subreport connection in iReport. Often this is sufficient to pass the data source.
But you might need a little code to handle things. Consider this example with a CSV data source re-used in subreports. The reason why you can't just use the JRParameter.REPORT_DATA_SOURCE object is because the index row pointer is never reset, so passing that original object into the subreport will bring the recordset to its close prematurely. We solved this with a minimal helper class:
package com.jaspersoft.untested_unsupported;
import java.io.File;
import java.io.FileNotFoundException;
import net.sf.jasperreports.engine.JRDataSource;
import net.sf.jasperreports.engine.data.JRCsvDataSource;
public class CsvDataSourceFactory {
public static JRDataSource getDataSource(String fileName, boolean firstRowHeaders) throws FileNotFoundException {
JRCsvDataSource csvDs = new JRCsvDataSource(new File(fileName));
csvDs.setUseFirstRowAsHeader(firstRowHeaders);
return csvDs;
}
}
You can pass datasource via the built-in REPORT_DATA_SOURCE
parameter.
The example:
<subreport>
<reportElement x="261" y="25" width="200" height="100"/>
<dataSourceExpression><![CDATA[$P{REPORT_DATA_SOURCE}]]></dataSourceExpression>
<subreportExpression><![CDATA[$P{SUBREPORT_DIR} + "subreport.jasper"]]></subreportExpression>
</subreport>
You can create new instance of datasource based on variable, parameter or field.
The sample:
<variable name="HeadingsCollection" class="java.util.Collection" calculation="System">
<initialValueExpression><![CDATA[new java.util.ArrayList()]]></initialValueExpression>
</variable>
...
<subreport>
<reportElement x="0" y="0" width="515" height="20"/>
<subreportParameter name="ReportTitle">
<subreportParameterExpression><![CDATA[$P{ReportTitle}]]></subreportParameterExpression>
</subreportParameter>
<dataSourceExpression><![CDATA[new net.sf.jasperreports.engine.data.JRBeanCollectionDataSource($V{HeadingsCollection})]]></dataSourceExpression>
<subreportExpression class="java.lang.String"><![CDATA["HeadingsReport.jasper"]]></subreportExpression>
</subreport>
Another sample:
<field name="cast" class="java.util.Collection"/>
...
<subreport>
<reportElement positionType="Float" x="15" y="25" width="245" height="20" isRemoveLineWhenBlank="true" backcolor="#99CCFF"/>
<dataSourceExpression><![CDATA[new net.sf.jasperreports.engine.data.JRBeanCollectionDataSource($F{cast})]]></dataSourceExpression>
<subreportExpression class="java.lang.String"><![CDATA["JRMDbCastSubreport.jasper"]]></subreportExpression>
</subreport>
Or you can pass the datasource via the parameter:
<parameter name="SubreportDataSource" class="net.sf.jasperreports.engine.JRDataSource"/>
...
<subreport>
<reportElement positionType="Float" x="15" y="25" width="245" height="20" isRemoveLineWhenBlank="true"/>
<dataSourceExpression>$P{SubreportDataSource}</dataSourceExpression>
<subreportExpression class="java.lang.String"><![CDATA["Subreport.jasper"]]></subreportExpression>
</subreport>
Note: Using the same (with master report) datasource in subreport can cause the effect of loosing the first row in the subreport. You can read Why is the first record missing from my subreport? post for understanding how to avoid this issue.