I am creating a simple reporting program using java and iReport (from jasper), which is supposed to create a report in pdf showing PCs with their IP address, their location, whether it's idle or not at the moment (handled by another system), and a list of projects it is currently attached to (managed elsewhere, too).
I'm using iReport for this matter, and have created a dummy collection generating class as follows:
public class PCReports {
public static java.util.Collection PC_collection;
public static java.util.Collection generateCollection() {
PC_collection = new ArrayList<PCLineDTO>();
PCLineDTO line = new PCLineDTO();
line.setIP("192.168.1.1");
line.setLab("location");
line.setActive(true);
line.addProjectName("project1");
line.addProjectName("project2");
line.addProjectName("project3");
PC_collection.add(line);
line = new PCLineDTO();
line.setIp("192.168.1.2");
line.setLab("location2");
line.setActive(false);
line.addProjectName("project1");
line.addProjectName("project2");
PC_collection.add(line);
return PC_collection;
}
}
The entity class in this case being:
public class PCLineDTO {
private String ip;
private String lab;
private Boolean active;
private ArrayList<String> projects;
}
After some searching around the Internet, I found a way to do something similar, using subreports.
The thing is, I don't know how to print a collection of strings passed as a dataSource to this subreport.
In the examples I found on the Internet, for each item in the master collection, the subreports were passed a collection of objects -with their own getter methods for each attribute- instead of a collection of strings as is the case here. In those cases, they accessed the values they needed to use via the iReport syntax, which I was not able to use, for example:
$F{project}
Since iReport looks for a getProject method contained within the objects it receives, but in this case it's a simple String object (without a getProject method, as it were).
Use a subreport or a subdataset.
Pass the subreport a collection datasource
JRBeanCollectionDataSource($F{Projects})
Then in the new subreport create a new field called "_THIS" exactly, this means the bean in the collection passed is the same as the value i want
For more info, check the source code of the class here: JRAbstractBeanDataSource
Note: this is available in JasperReport 3.0.0 im not sure if it exists in previous builds.
Hope this helps
Update: just checked the SVN, seems like this feature is implemented in JasperReports 2.0.0
Interesting. I think you'd better use the List, and then define getName() on the Project class. Then in the subreport define a variable "name". It will work this way, and it will allow you to add easily additional information, like project duration, team-lead, etc.
As Bozho says, in case proyects
was an array of complex object you should reference it as a field of type java.util.Collection
an then pass it to the inner subreport the same way medopal indicates. And don´t put the _THIS field.
To elaborate on this without using _THIS: let's say a java bean has a list of subBeans and this subBean has a complex format and we want to print each subBean in a custom way. I quote an example where the subDataset element is on the report level and the componentElement is in the detail band:
<subDataset name="ListOfSubBeans" uuid="66c86e41-c565-4f18-bccf-1a1b2a567585">
<field name="subBeanField_1" class="java.lang.String">
<fieldDescription><![CDATA[subBeanField_1]]></fieldDescription>
</field>
</subDataset>
...
<componentElement>
<reportElement x="780" y="0" width="100" height="30" uuid="f73864b9-46dd-4adb-8dad-a6bd8dfae64e">
<property name="net.sf.jasperreports.export.headertoolbar.table.name" value=""/>
</reportElement>
<jr:list xmlns:jr="http://jasperreports.sourceforge.net/jasperreports/components" xsi:schemaLocation="http://jasperreports.sourceforge.net/jasperreports/components http://jasperreports.sourceforge.net/xsd/components.xsd" printOrder="Vertical">
<datasetRun subDataset="ListOfSubBeans" uuid="a8dd1c2b-3ac0-4ffa-b9d0-08e4890e199a">
<dataSourceExpression><![CDATA[new net.sf.jasperreports.engine.data.JRBeanCollectionDataSource($F{listOfSubBeans})]]></dataSourceExpression>
</datasetRun>
<jr:listContents height="30" width="100">
<textField>
<reportElement x="0" y="0" width="100" height="30" uuid="61700c18-6bb9-45da-a235-b76b9f76a2ea"/>
<textFieldExpression><![CDATA[$F{subBeanField_1}]]></textFieldExpression>
</textField>
</jr:listContents>
</jr:list>
</componentElement>
...
So, the master dataset has declared that the master bean has a member variable that is a list: listOfSubBeans
. This java.util.List is used to feed the datasource of the jr:list
, while the fields of the jr:list
are declared using a subDataset called ListOfSubBeans
(pay attention to case sensitivity).