2

If I have a Jasper report with two fields. For example:

<field name="counts" class="java.util.List"/>
<field name="names" class="java.util.List"/>

In the report is it possible to use the name field to "lookup" a value in the counts field if the counts field looks like this:

[{"Bob":10},{"Bill":5},{"John":2}]

So in the report I iterate over the names using a subDataSet:

<subDataset name="nameDetails" uuid="6f0e513d-9659-4dea-8c88-0fa9522d6aef">
    <field name="name" class="java.lang.String">
        <fieldDescription><![CDATA[name]]></fieldDescription>
    </field>
</subDataset>

<componentElement>
    <reportElement x="0" y="40" width="200" height="60"/>
    <jr:list printOrder="Vertical">
       <datasetRun subDataset="nameDetails">
            <dataSourceExpression><![CDATA[new net.sf.jasperreports.engine.data.JRMapCollectionDataSource($F{names})]]></dataSourceExpression>
       </datasetRun>
       <jr:listContents height="60" width="200">
           <textField>
                <reportElement x="0" y="0" width="200" height="20"/>
                <textFieldExpression><![CDATA["Name: " + $F{name}]]></textFieldExpression>
           </textField>
       ...

This prints out the name of each person in the names field, but additionally I want to use the "name" of each person to look-up the count for the person in the counts field, but not sure if I can do this or how?

Petter Friberg
  • 21,252
  • 9
  • 60
  • 109
Sean Barry
  • 61
  • 2
  • 6

1 Answers1

2

Yes you can reference fields, in your case however you need first to pass also the other field to the subdataset, hence you can only reference data that is present in the actual subdataset.

One way is to pass the field counts as a parameter.

<datasetParameter name="counts">
   <datasetParameterExpression><![CDATA[$F{counts}]]></datasetParameterExpression>
</datasetParameter>

For example assuming the List have data in same position.

List<String> names = Arrays.asList(new String[] { "Bob", "Bill", "John" });
List<Integer> counts = Arrays.asList(new Integer[] { 10, 5, 2 });

You could use the built in parameter $V{REPORT_COUNT} to retrive data from the other List, $P{counts}.get(($V{REPORT_COUNT}.intValue()-1))

jrxml

<?xml version="1.0" encoding="UTF-8"?>
<jasperReport xmlns="http://jasperreports.sourceforge.net/jasperreports" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://jasperreports.sourceforge.net/jasperreports http://jasperreports.sourceforge.net/xsd/jasperreport.xsd" name="firstReport" pageWidth="595" pageHeight="842" whenNoDataType="BlankPage" columnWidth="555" leftMargin="20" rightMargin="20" topMargin="20" bottomMargin="20" uuid="597c0716-df6b-42ec-a7c8-863eb1b7174a">
    <subDataset name="nameDetails" uuid="63078d78-2076-4a72-8728-ee6ca3ded99f">
        <parameter name="counts" class="java.util.List"/>
        <field name="_THIS" class="java.lang.String"/>
    </subDataset>
    <field name="counts" class="java.util.List"/>
    <field name="names" class="java.util.List"/>
    <detail>
        <band height="50">
            <componentElement>
                <reportElement x="0" y="0" width="550" height="30" uuid="180fb785-64b3-4f04-81f6-7076444d871d"/>
                <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="nameDetails" uuid="8d40297b-e33b-4681-9533-d6f1ab63c6f2">
                        <datasetParameter name="counts">
                            <datasetParameterExpression><![CDATA[$F{counts}]]></datasetParameterExpression>
                        </datasetParameter>
                        <dataSourceExpression><![CDATA[new net.sf.jasperreports.engine.data.JRBeanCollectionDataSource($F{names})]]></dataSourceExpression>
                    </datasetRun>
                    <jr:listContents height="30" width="550">
                        <textField>
                            <reportElement x="0" y="0" width="550" height="30" uuid="48e09c52-3b6a-40cf-b572-2abccfcd83cc"/>
                            <textElement verticalAlignment="Middle">
                                <font size="14"/>
                            </textElement>
                            <textFieldExpression><![CDATA[$F{_THIS} + ":" + $P{counts}.get(($V{REPORT_COUNT}.intValue()-1))]]></textFieldExpression>
                        </textField>
                    </jr:listContents>
                </jr:list>
            </componentElement>
        </band>
    </detail>
</jasperReport>

Result

Output

Note: If you have control on data arriving, however I would strongly suggest you pass the data in a single object (List), since this type of referencing is error prone, in this case if the size of the Lists are different, the report generation will fail

Petter Friberg
  • 21,252
  • 9
  • 60
  • 109
  • Thanks. Looks good. I can look to combine the lists in a MongoDB query. The example I’ve given is a bit simplified. I want to use the value of a nested field - an ID to look up another value in the other list. The one list contains the details and ID of something and I use the ID to find the count value in the second list. All I have is what I can do in a MongoDB aggregation query - to combine two different datasets and the Jasper report itself. I don’t, unfortunately, have a Java application to do any processing. – Sean Barry Nov 18 '20 at 21:37