I have a main report with 2 subreports. I am using a custom datasource to fetch the report contents. But only one subreport gets displayed when the main report is previewed
The Problem was with trying to use the same datasource for multiple subreports. The datasource gets exhausted for the first subreport and so no data is available for the subsequent sub reports.
Solution :
You have to rewind the datasource using JRRewindableDataSource
Thanks to lucianc Community answer
Summarizing on the tasks :
Create a wrapper RewindableDSWrapper that rewinds a data source and delegates all the calls to it.
package com.jasper.api;
import net.sf.jasperreports.engine.JRException;
import net.sf.jasperreports.engine.JRField;
import net.sf.jasperreports.engine.JRRewindableDataSource;
public class RewindableDSWrapper implements JRRewindableDataSource {
private final JRRewindableDataSource ds;
public RewindableDSWrapper(JRRewindableDataSource ds) {
this.ds = ds;
try {
this.ds.moveFirst();
} catch (JRException e) {
e.printStackTrace();
}
}
public boolean next() throws JRException {
return ds.next();
}
public Object getFieldValue(JRField jrField) throws JRException {
return ds.getFieldValue(jrField);
}
public void moveFirst() throws JRException {
ds.moveFirst();
}
}
In your custom data source class implement JRRewindableDataSource interface.
public void moveFirst() throws JRException {
// provide logic for rewinding datasource
}
In your jrxml file, if your datasource is custom one then
<dataSourceExpression><![CDATA[new com.jasper.api.RewindableDSWrapper((JRRewindableDataSource)$P{REPORT_DATA_SOURCE})]]></dataSourceExpression>
you cast REPORT_DATA_SOURCE to JRRewindableDataSource as the compiler will try to cast it to JRDataSource.
Also add the jar file containing RewindableDSWrapper class to classpath in your studio.
I've found an alternative solution which doesn't require additional java classes. If your data source is a JRBeanCollectionDataSource
you can call the method cloneDataSource()
inside the dataSourceExpression field like this:
<dataSourceExpression><![CDATA[$P{REPORT_DATA_SOURCE}.cloneDataSource()]]></dataSourceExpression>
This will instantiate a new iterator which is the same thing that happens in the moveFirst()
method.
documentation