I'm trying to implement table of contents in my Jasper report. Here is an example offered on Jasper Reports site of how to do it: https://sourceforge.net/p/jasperreports/code/ci/jr-6-2-1/tree/jasperreports/demo/samples/tableofcontents/reports/
In the example above they run a query against a db to obtain data to fill the report part*. In my case I need to fill the report part with data obtained from JavaBean and I can't find a solution to it.
I figured out how to pass a datasource from a wrapping report to a report part as a parameter but I don't know how to use it there so that all report part fields are mapped to it. Regularly (without report parts) as far as I know it is done automatically.
What I have done so far:
JasperCompileManager.compileReportToFile("TablePart.jrxml", "TablePart.jasper");
JasperReport jasperReport = JasperCompileManager.compileReport("TableOfContentsReport.jrxml");
JRBeanCollectionDataSource dataSource = new JRBeanCollectionDataSource(generateBeanList());
JasperPrint jasperPrint = JasperFillManager.fillReport(jasperReport, new HashMap<>(), dataSource);
JasperExportManager.exportReportToPdfFile(jasperPrint, "TableOfContentsReport.pdf");
public class MyBean {
private Integer orderId;
private String shipName;
private String shipCity;
private String shipCountry;
private Integer total;
public Integer getOrderId() {
return orderId;
}
public void setOrderID(Integer orderId) {
this.orderId = orderId;
}
public String getShipName() {
return shipName;
}
public void setShipName(String shipName) {
this.shipName = shipName;
}
public String getShipCity() {
return shipCity;
}
public void setShipCity(String shipCity) {
this.shipCity = shipCity;
}
public String getShipCountry() {
return shipCountry;
}
public void setShipCountry(String shipCountry) {
this.shipCountry = shipCountry;
}
public Integer getTotal() {
return total;
}
public void setTotal(Integer total) {
this.total = total;
}
}
<jasperReport ... sectionType="Part" ...>
<group name="dummy">
<groupExpression><![CDATA[]]></groupExpression>
<groupHeader>
...
<part>
<p:subreportPart xmlns:p="http://jasperreports.sourceforge.net/jasperreports/parts" xsi:schemaLocation="http://jasperreports.sourceforge.net/jasperreports/parts http://jasperreports.sourceforge.net/xsd/parts.xsd"
usingCache="true">
<subreportParameter name="REPORT_DATA_SOURCE">
<subreportParameterExpression><![CDATA[$P{REPORT_DATA_SOURCE}]]></subreportParameterExpression>
</subreportParameter>
<subreportExpression><![CDATA["TablePart.jasper"]]></subreportExpression>
</p:subreportPart>
</part>
</groupHeader>
</group>
</jasperReport>
I found it is possible to pass the datasource from the wrapping report to the report part as a parameter: $P{REPORT_DATA_SOURCE}
But how can I use it in the report part to map corresponding fields (Jasper Reports fields to JavaBean fields)? The way it is now all the declared fields in the report part evaluate to null.
<jasperReport ...>
<queryString><![CDATA[]]></queryString>
<field name="orderId" class="java.lang.Integer"/>
<field name="shipName" class="java.lang.String"/>
<field name="shipCity" class="java.lang.String"/>
<field name="shipCountry" class="java.lang.String"/>
...
</jasperReport>
These are the fields (orderId, shipName, etc) I need to be set with the corresponding values of the passed JavaBean.
*Just in case, here is a reference on the report parts subject: http://jasperreports.sourceforge.net/sample.reference/book/index.html
The problem is that the datasource you are passing to the subreport is already consumed.
The JRDatasource uses next to iterate the detail band in main report and when it is passed to subreport its at the end.
Solution:
Pass to main report a new JREmptyDataSource(1)
, only 1 record is needed
Pass your datasource as parameter in the HashMap<String,Object>
es map.put("subreportDataSource",dataSource)
Pass to subreport this datasource
<subreportParameter name="REPORT_DATA_SOURCE">
<subreportParameterExpression><![CDATA[$P{subreportDataSource}]]></subreportParameterExpression>
</subreportParameter>
Follow up question
is it possible to kind of share one datasource between all report parts?
Not directly as datasource but in your case you could pass the generateBeanList()
as a parameter map.put("dsList",generateBeanList())
and then to each subreport pass new JRBeanCollectionDataSource($P{dsList})