How do I print a list of strings contained within another list in iReport? - jasper-reports

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).

Related

What happens if I have same duplicate UUID in report?

In my jasper report, I am using elements something like this:
<textField isStretchWithOverflow="true">
<reportElement style="alternateStyle" positionType="Float" stretchType="RelativeToTallestObject" x="292" y="0" width="85" height="30" uuid="b93b4e99-d6fb-4679-836d-9b198cb5fe1c"/>
<textElement textAlignment="Center" verticalAlignment="Middle">
<font fontName="SMCustomFont" size="9" isBold="false"/>
<paragraph leftIndent="3"/>
</textElement>
<textFieldExpression><![CDATA[($F{SOMEEXP}]]></textFieldExpression>
</textField>
Here the uuid is "b93b4e99-d6fb-4679-836d-9b198cb5fe1c".
My question is What happens if I keep the UUID same for some other textField element in the same JRXML file and what is the significance of UUID?
When I tried, the report is generating fine.
Jasper reports use the UUID in the engine to identify elements, see for example SortElementJsonHandler.getCurrentSortField.
A Friendly User (staff) at the Jasper Community forum states
UUID is used mostly for the interactive elements like tables and crosstabs to identify the elements for sorting/filtering/etc. It's used in the viewer and on the engine level, I am not sure there is useful API available to interact with elements using UUID.
Also as far as I can see, in most simple cases like two textField there is no problem having same UUID, but you can get strange result if you have a more complex design with multiple similar components and all of them have same UUID
Use the IDE and you don't need to worry about it.
If you copy and past elements/components in the raw jrxml, either change a number or remove the UUID, when saved in JasperSoft Studio it will auto-generate it for you if it does not exists. Overall I would suggest that you use the IDE for all actions (copy and past etc), personally I only use the code/jrxml view if I need to do some quick replace of something etc.

jasper decimal separator being ignored

In a jasper report I use a JSON datasource.
This datasource contains numbers (e.g. 159.994).
There is a field of class java.lang.double (let's call it "doubleField") and a text field with this field and a pattern ("#,##0.00 ¤ (brutto)").
The pattern works fine (german currency format) but if I print out just the value of the doubleField the expected output would be "195,99" or "159.994".
But in fact it is "159.994,00" or "159994.0".
There was a solution changing the language of the report from "groovy" to "JavaScript" but this won't help and is also not applicable.
There is a "quick&dirty" solution (without being quick) to just take the JSON value as a String and then cast it to a double in the text field. This works fine but it's dirty and not really quick.
Any ideas?
I have a Jasper report definition. I'm just including a few things from that report definition that I think might be relevant to your problem.
First, I have several field definitions. Here are two of them:
<field name="FundFixedBeginningBalance" class="java.lang.Double">
<fieldDescription>
<![CDATA[FundFixedBeginningBalance/FundFixedBeginningBalanceValue]]>
</fieldDescription>
</field>
<field name="FundNonFixedBeginningBalance" class="java.lang.Double">
<fieldDescription>
<![CDATA[FundNonFixedBeginningBalance/FundNonFixedBeginningBalanceValue]]>
</fieldDescription>
</field>
Note how both are defined with class="java.lang.Double". I'm using XPath expressions because my data is in XML, but that is not fundamentally different from JSON. Later, in the report layout section I have:
<textField pattern="#,##0.00 ;(#,##0.00)" isBlankWhenNull="true">
<reportElement positionType="Float" x="368" y="52" width="100" height="14" uuid="deac984d-39b8-49f4-b4d2-28e66681c098">
<property name="local_mesure_unitx" value="pixel"/>
<property name="com.jaspersoft.studio.unit.x" value="px"/>
</reportElement>
<textElement textAlignment="Right"/>
<textFieldExpression><![CDATA[$F{FundFixedBeginningBalance} + $F{FundNonFixedBeginningBalance}]]></textFieldExpression>
</textField>
Notice there is no casting within the textFieldExpression element; just substituting both fields in with $F and adding them together (and this prints correctly). Are you doing something different?

Grouping by parameter value in jasper

Well, I don't know, maybe I'm missing something, but I've been trying to group data in a jasper report, but so far the grouping appears only if the group expression is a field. Is it possible to group data by parameter value instead of field value? i.e., something like
<groupExpression><[!CDATA[$P{some_param}]]></groupExpression>
instead of
<groupExpression><[!CDATA[$F{some_field}]]></groupExpression>
in the .jrxml file?
Is it possible to group data by parameter value instead of field value?
Yes, it is, just like you mentioned. You would have no syntax errors and the report would be generated.
The problem is that it may not bring what you're expecting. The group bands are usually printed every time the "groupExpression" changes. So basically this parameter needs to be associated with something that will change during the report generation (for example, filling a parameter of a subreport with a field in way that this subreport uses this paramater as a group expression). And of course, it needs to be associated with something that makes sense and bring you the desirable behavior.
You can have something like this in your subreport:
...
<parameter name="START" class="java.util.Date"/>
<parameter name="END" class="java.util.Date"/>
...
And something like this in a detail band of your "super" report:
<subreport>
<reportElement x="0" y="10" width="555" height="200" uuid="ac2c99da-f595-4498-a518-2bfb1f31b73c"/>
<subreportParameter name="START">
<subreportParameterExpression><![CDATA[$F{start}]]></subreportParameterExpression>
</subreportParameter>
<subreportParameter name="END">
<subreportParameterExpression><![CDATA[$F{end}]]></subreportParameterExpression>
</subreportParameter>
...
</subreport>
Just notice I'm assuming the fields $F{end} and $F{start} are also "java.util.Date" objects.

How to pass date as a field in jrxml of JasperReports?

I want to pass date as a field to the jrxml.
Following is the code for it.
<xyLineChart>
<chart evaluationTime="Band">
<reportElement x="0" y="0" width="555" height="500"/>
</chart>
<xyDataset>
<dataset incrementType="None"/>
<xySeries>
<seriesExpression><![CDATA["CpuUsageGraph"]]></seriesExpression>
<xValueExpression><![CDATA[new java.util.Date($F{time}.getTime())]]></xValueExpression>
<yValueExpression><![CDATA[$F{cpuUsage}]]></yValueExpression>
</xySeries>
</xyDataset>
<linePlot>
<plot/>
</linePlot>
</xyLineChart>
But it is not working.
Its giving error as can not cast from date to number.
Then how to convert it?
You are using the time field in the constructor of Date. No need for that.
Instead of this:
java.util.Date($F{time}.getTime())
use this:
$F{time}
If you want the long value of it: then use this
$F{time}.getTime()
UPDATE
I didn't notice you are using a chart, here is a new answer:
In charts, X and Y value expressions should be any Number object, check subclasses in Number Class JavaDoc, in your case you are getting the long value of your Time field, which cannot be cast to Number, you will need to define a new object, for example:
new Long($F{time}.getTime())
Side Note: in this case the report will compile and work, BUT, you are getting the number of milliseconds and using it in your chart. I don't think that is what you want exactly. So i would suggest extracting a specific field from your Date field like Day. Month, Year ... etc
I cannot see the attached JRXML. However, open your JRXML file in a text editor, and check that the field is defined something like this:
<field name="MyDate" class="java.util.Date"/>

Accessing/importing user defined classes in jrxml

Have anyone tried to import user defined classes in jasper report (.jrxml file)?
I want to use some (user defined) Util class inside my jasper report to cook some bean attributes. I am using Javabean datasource
Please let me know if you need further clarification.
syntax to import class is
<import value="java.util.HashMap"/>
I want to use
<import value="mypackage.MyUtil" />
....
....
<field name="myVar" class="java.lang.String">
<fieldDescription><![CDATA[MyUtil.cook(myData)]]>
</fieldDescription>
</field>
The simple definition for MyUtil.java could be
package mypackage;
public class MyUtil
{
public static String cook(String data)
{
return data + "_cooked";
}
}
I think I should have tried sufficiently before asking this.
There is nothing extra needed apart from
There are two sections in jrxml:
1. Defining fields from javabean source
2. Using fields defined in step 1. to populate values in detail band
I was trying to cook the value of javabean members even before they are used to create fields
So, jasper was trying to parse that 'expression' as javabean member.
Following is wrong
<field name="myVar" class="java.lang.String">
<fieldDescription><![CDATA[MyUtil.cook(myData)]]>
</fieldDescription>
</field>
When I used the Util class on field value, it worked.
<textField>
<reportElement x="200" y="0" width="100" height="13"/>
<textElement/>
<textFieldExpression class="java.lang.String">
<![CDATA[MyUtil.cook($F{myVar})]]>
</textFieldExpression>
</textField>
Thanks
Nayn
You have to set the classpath in your iReport. It depends on its version, but is generally under Settings/Classpath