Hot questions for Using JasperReports in jaspersoft studio

Top Java Programmings / JasperReports / jaspersoft studio

Question:

After being able to add custom data source from java bean to a report according to Add custom data source to Jaspersoft Studio , I get to the second point of my reporting with jasper.

I have a main report which uses a data base as its data source. Then I add a bean.xml data source to the report and add a table to the main report which uses this bean.xml data source to get java beans.

My goal is to get a field value from the main report and manipulate its value, then fill the beans with these values and at last fill the table with the beans.

To do this I have written 3 classes which I use as Scriptlet in the table data set:

This is an illustration of what I need to do:

The problem is in FillTable class, when I us String kNFormelGG = (String) this.getParameterValue("gg"); the created bean.xml fails the test connection with java.lang.reflect.InvocationTargetException

Caused by: java.lang.NullPointerException
at net.sf.jasperreports.engine.JRAbstractScriptlet.getParameterValue(JRAbstractScriptlet.java:95)
at net.sf.jasperreports.engine.JRAbstractScriptlet.getParameterValue(JRAbstractScriptlet.java:86)
at org.iqtig.reporting.dataSource.bean.dataSourceXML.FillTable.fillTable(FillTable.java:45)
at org.iqtig.reporting.dataSource.bean.dataSourceXML.JRDataSourceFactory.createCollection(JRDataSourceFactory.java:27)
... 34 more

If I assign a fix value like String kNFormelGG ="Test me" the bean connection encounters no error and after assigning bean.xml as the value for Default Data Adapter in Dataset1 it fills the table with static values. How can get the data from a parameter or a value dynamically from the main report data source and use it in beans? I have this assumption that at the time of calling the static factory class from my adapter, the fields are still empty. Maybe I am wrong but I do not find any other declaration for this problem.

BeanFactory Class

import java.util.Collection;
import net.sf.jasperreports.engine.JRDefaultScriptlet;
import net.sf.jasperreports.engine.JRScriptletException;

/**
 * Factory for TableCellsBean Klasse
 *
 * @author iman.gharib
 */

public class JRDataSourceFactory extends JRDefaultScriptlet {

/**
 * @return collection der TableCellsBean Objekten
 * @throws JRScriptletException
 */
public static Collection<TableCellsBean> createCollection()
        throws JRScriptletException {
    FillTable ft = new FillTable();
    Collection<TableCellsBean> reportRows = ft.fillTable();
    return reportRows;
}

}

Bean Class

public class TableCellsBean {

private String fieldName;
private String keyFormel;
private String mK;
private String notation;
private String item;

/**
 * Constructor.
 *
 * @param fieldName
 * @param keyFormel
 * @param mK
 * @param notation
 * @param item
 */
public TableCellsBean(final String fieldName, final String keyFormel, final String mK, final String notation, final String item) {
    this.fieldName = fieldName;
    this.keyFormel = keyFormel;
    this.mK = mK;
    this.notation = notation;
    this.item = item;
}

/**
 * Constructo Leer
 */
public TableCellsBean() {

}
public TableCellsBean getme() {
    return this;
}
// getter and setters
}

Class for preparing and creating beans

public class FillTable extends JRDefaultScriptlet {
@Override
public void afterColumnInit()
        throws JRScriptletException {
    fillTable();
}
public ArrayList<String> splitGGArray(final String kNFormelGG) {
    ArrayList<String> fieldNames = new ArrayList<>();
    String[] array = (kNFormelGG.split(" "));
    for (String sub : array) {
        fieldNames.add(sub);
    }
    return fieldNames;
}
public Collection<TableCellsBean> fillTable()
        throws JRScriptletException {
 // gg is a parameter for table dataset. It is mapped to KN_FormelGG
 // which comes from the main report data base 
    String kNFormelGG = (String) this.getParameterValue("gg");
    List<TableCellsBean> listTableCells = new ArrayList<>();
    // TableCellsBean tableCell = new TableCellsBean();
    for (String fn : splitGGArray(kNFormelGG)) {
        listTableCells.add(new TableCellsBean(fn, fn, fn, fn, fn));
        // listTableCells.add(tableCell);
    }
    // JRBeanCollectionDataSource tableCellJRBean = new JRBeanCollectionDataSource(listTableCells);
    // Map<String, Object> parameters = new HashMap<>();
    // parameters.put("FieldDataSource", tableCellJRBean);
    return listTableCells;
}
}

JRXML

<?xml version="1.0" encoding="UTF-8"?>
<!-- Created with Jaspersoft Studio version 6.3.0.final using JasperReports Library version 6.3.0  -->
<!-- 2016-08-08T14:30:03 -->
<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="main" pageWidth="595" pageHeight="842" columnWidth="555" leftMargin="20" rightMargin="20" topMargin="20" bottomMargin="20" uuid="4f1480cf-f8f9-420f-96b4-7fc1e41e791b">
    <property name="com.jaspersoft.studio.data.sql.tables" value=""/>
    <property name="com.jaspersoft.studio.data.defaultdataadapter" value="QIDBReport"/>
    <style name="Table_TH" mode="Opaque" backcolor="#F0F8FF">
        <box>
            <pen lineWidth="0.5" lineColor="#000000"/>
            <topPen lineWidth="0.5" lineColor="#000000"/>
            <leftPen lineWidth="0.5" lineColor="#000000"/>
            <bottomPen lineWidth="0.5" lineColor="#000000"/>
            <rightPen lineWidth="0.5" lineColor="#000000"/>
        </box>
    </style>
    <style name="Table_CH" mode="Opaque" backcolor="#BFE1FF">
        <box>
            <pen lineWidth="0.5" lineColor="#000000"/>
            <topPen lineWidth="0.5" lineColor="#000000"/>
            <leftPen lineWidth="0.5" lineColor="#000000"/>
            <bottomPen lineWidth="0.5" lineColor="#000000"/>
            <rightPen lineWidth="0.5" lineColor="#000000"/>
        </box>
    </style>
    <style name="Table_TD" mode="Opaque" backcolor="#FFFFFF">
        <box>
            <pen lineWidth="0.5" lineColor="#000000"/>
            <topPen lineWidth="0.5" lineColor="#000000"/>
            <leftPen lineWidth="0.5" lineColor="#000000"/>
            <bottomPen lineWidth="0.5" lineColor="#000000"/>
            <rightPen lineWidth="0.5" lineColor="#000000"/>
        </box>
    </style>
    <subDataset name="Dataset1" uuid="5677929d-813b-4d39-828c-de966a9d7689">
        <property name="com.jaspersoft.studio.data.defaultdataadapter" value="bean.xml"/>
        <property name="net.sf.jasperreports.data.adapter" value="bean.xml"/>
        <scriptlet name="Scriptlet_1" class="org.iqtig.reporting.dataSource.bean.mapBeanAsDatasource.JRDataSourceFactory"/>
        <parameter name="gg" class="java.lang.String"/>
        <field name="item" class="java.lang.String">
            <fieldDescription><![CDATA[item]]></fieldDescription>
        </field>
        <field name="fieldName" class="java.lang.String">
            <fieldDescription><![CDATA[fieldName]]></fieldDescription>
        </field>
        <field name="me" class="org.iqtig.reporting.dataSource.bean.dataSourceXML.TableCellsBean">
            <fieldDescription><![CDATA[me]]></fieldDescription>
        </field>
        <field name="keyFormel" class="java.lang.String">
            <fieldDescription><![CDATA[keyFormel]]></fieldDescription>
        </field>
        <field name="mK" class="java.lang.String">
            <fieldDescription><![CDATA[mK]]></fieldDescription>
        </field>
    </subDataset>
    <parameter name="LB_ID" class="java.lang.Integer">
        <defaultValueExpression><![CDATA[62]]></defaultValueExpression>
    </parameter>
    <parameter name="KN_OffeziellGruppe" class="java.lang.Integer">
        <defaultValueExpression><![CDATA[3]]></defaultValueExpression>
    </parameter>
    <parameter name="FieldDataSource" class="net.sf.jasperreports.engine.data.JRBeanCollectionDataSource" isForPrompting="false"/>
    <parameter name="KN_FormelGG" class="java.lang.String" isForPrompting="false"/>
    <queryString>
        <![CDATA[select * from "KennzahlReferenz2015_QIBericht",  "Images" 
where LB_ID =  $P{LB_ID} 
and KN_OffiziellGruppe =  $P{KN_OffeziellGruppe}
and  IMG_ID = 1]]>
    </queryString>
    <field name="QI_Praefix" class="java.lang.String"/>
    <field name="KN_Id" class="java.lang.Integer"/>
    <field name="bewertungsArtTypNameKurz" class="java.lang.String"/>
    <field name="refbereich" class="java.lang.String"/>
    <field name="refbereichVorjahres" class="java.lang.String"/>
    <field name="KN_GGAlleinstehend" class="java.lang.String"/>
    <field name="erlaueterungDerRechregeln" class="java.lang.String"/>
    <field name="teildatensatzbezug" class="java.lang.String"/>
    <field name="mindesanzahlZaeler" class="java.lang.Integer"/>
    <field name="mindesanzahlNenner" class="java.lang.Integer"/>
    <field name="KN_FormelZ" class="java.lang.String"/>
    <field name="KN_FormelGG" class="java.lang.String"/>
    <field name="verwendeteFunktionen" class="java.lang.String"/>
    <field name="idLb" class="java.lang.String"/>
    <field name="LB_LangBezeichnung" class="java.lang.String"/>
    <field name="LB_ID" class="java.lang.Integer"/>
    <field name="nameAlleinstehend" class="java.lang.String"/>
    <field name="KN_BezeichnungAlleinstehendKurz" class="java.lang.String"/>
    <field name="QI_ID" class="java.lang.Integer"/>
    <field name="IMG_ID" class="java.lang.Integer"/>
    <field name="Name" class="java.lang.String"/>
    <field name="Image" class="java.lang.Object"/>
    <group name="id" isStartNewPage="true">
        <groupExpression><![CDATA[$F{KN_Id}]]></groupExpression>
        <groupHeader>
            <band height="44"/>
        </groupHeader>
        <groupFooter>
            <band height="50"/>
        </groupFooter>
    </group>
    <background>
        <band splitType="Stretch"/>
    </background>
    <title>
        <band height="44" splitType="Stretch"/>
    </title>
    <pageHeader>
        <band height="35" splitType="Stretch"/>
    </pageHeader>
    <columnHeader>
        <band height="34" splitType="Stretch"/>
    </columnHeader>
    <detail>
        <band height="149" splitType="Stretch">
            <componentElement>
                <reportElement x="170" y="20" width="350" height="100" uuid="38d917fb-dfc2-4c08-890a-09cfe6e2214d">
                    <property name="com.jaspersoft.studio.layout" value="com.jaspersoft.studio.editor.layout.VerticalRowLayout"/>
                    <property name="com.jaspersoft.studio.table.style.table_header" value="Table_TH"/>
                    <property name="com.jaspersoft.studio.table.style.column_header" value="Table_CH"/>
                    <property name="com.jaspersoft.studio.table.style.detail" value="Table_TD"/>
                    <property name="net.sf.jasperreports.export.headertoolbar.table.name" value=""/>
                    <property name="com.jaspersoft.studio.components.autoresize.proportional" value="true"/>
                </reportElement>
                <jr:table xmlns:jr="http://jasperreports.sourceforge.net/jasperreports/components" xsi:schemaLocation="http://jasperreports.sourceforge.net/jasperreports/components http://jasperreports.sourceforge.net/xsd/components.xsd" whenNoDataType="AllSectionsNoDetail">
                    <datasetRun subDataset="Dataset1" uuid="1b3548f6-7d6b-4070-bb8e-aaefbabdc7c9">
                        <datasetParameter name="gg">
                            <datasetParameterExpression><![CDATA[$F{KN_FormelGG}]]></datasetParameterExpression>
                        </datasetParameter>
                    </datasetRun>
                    <jr:column width="70" uuid="048812d7-0ed1-4db8-a09a-e6242f77c6ce">
                        <property name="com.jaspersoft.studio.components.table.model.column.name" value="Column1"/>
                        <jr:tableHeader style="Table_TH" height="30" rowSpan="1"/>
                        <jr:detailCell style="Table_TD" height="30">
                            <textField>
                                <reportElement x="0" y="0" width="70" height="30" uuid="c5aaea84-1367-41df-be8d-7f71e3ea5153"/>
                                <textFieldExpression><![CDATA[$F{item}]]></textFieldExpression>
                            </textField>
                        </jr:detailCell>
                    </jr:column>
                    <jr:column width="70" uuid="11b85ada-c9fe-42b6-a646-8bd1697cdec2">
                        <property name="com.jaspersoft.studio.components.table.model.column.name" value="Column2"/>
                        <jr:tableHeader style="Table_TH" height="30" rowSpan="1"/>
                        <jr:detailCell style="Table_TD" height="30">
                            <textField>
                                <reportElement x="0" y="0" width="70" height="30" uuid="728ff44d-1dbd-404c-b8b3-7cc0e1f07f60"/>
                                <textFieldExpression><![CDATA[$F{fieldName}]]></textFieldExpression>
                            </textField>
                        </jr:detailCell>
                    </jr:column>
                    <jr:column width="70" uuid="892f30cb-fb41-444f-889b-1e005484c35e">
                        <property name="com.jaspersoft.studio.components.table.model.column.name" value="Column3"/>
                        <jr:tableHeader style="Table_TH" height="30" rowSpan="1"/>
                        <jr:detailCell style="Table_TD" height="30">
                            <textField>
                                <reportElement x="0" y="0" width="70" height="30" uuid="e38ac951-71bc-45a6-8ed2-313805a77050"/>
                                <textFieldExpression><![CDATA[$F{keyFormel}]]></textFieldExpression>
                            </textField>
                        </jr:detailCell>
                    </jr:column>
                    <jr:column width="70" uuid="7d0d700a-5a75-4c26-94c0-9ef7c53bd719">
                        <property name="com.jaspersoft.studio.components.table.model.column.name" value="Column4"/>
                        <jr:tableHeader style="Table_TH" height="30" rowSpan="1">
                            <textField>
                                <reportElement x="0" y="0" width="70" height="30" uuid="68577007-0344-406c-8aa2-3127d1da1c65"/>
                            </textField>
                        </jr:tableHeader>
                        <jr:detailCell style="Table_TD" height="30">
                            <textField>
                                <reportElement x="0" y="0" width="70" height="30" uuid="873d63c1-1b91-4441-b7bd-f67db7729e7f"/>
                                <textFieldExpression><![CDATA[$F{mK}]]></textFieldExpression>
                            </textField>
                        </jr:detailCell>
                    </jr:column>
                    <jr:column width="70" uuid="cf5a1a2f-594d-429f-8925-62d001e1dd00">
                        <property name="com.jaspersoft.studio.components.table.model.column.name" value="Column5"/>
                        <jr:tableHeader style="Table_TH" height="30" rowSpan="1">
                            <textField>
                                <reportElement x="0" y="0" width="70" height="30" uuid="7fb46eb8-d0e1-44ab-89f9-ec31d49b8109"/>
                                <textFieldExpression><![CDATA[$P{gg}]]></textFieldExpression>
                            </textField>
                        </jr:tableHeader>
                        <jr:detailCell style="Table_TD" height="30"/>
                    </jr:column>
                </jr:table>
            </componentElement>
            <textField>
                <reportElement x="20" y="80" width="100" height="30" uuid="b89cd04c-2569-43ef-9730-445b874855dd"/>
                <textFieldExpression><![CDATA[$F{KN_FormelGG}]]></textFieldExpression>
            </textField>
            <staticText>
                <reportElement x="20" y="32" width="100" height="30" uuid="e91b4461-5e53-4f85-8992-14e69a1aa05f"/>
                <text><![CDATA[KN_FormelGG]]></text>
            </staticText>
        </band>
    </detail>
    <columnFooter>
        <band height="45" splitType="Stretch"/>
    </columnFooter>
    <pageFooter>
        <band height="54" splitType="Stretch"/>
    </pageFooter>
    <summary>
        <band height="42" splitType="Stretch"/>
    </summary>
</jasperReport>

Answer:

My goal is to get a field value from the main report and manipulate its value, then fill the beans with these values and at last fill the table with the beans.

I will ignore all your scriplets and other code and show you the simplest way to create a dynamic datasource for another component using a current field, variable or parameter value.

As example we will have these String values in field1 (row1, row2)

Test1_1.23:Test2_4.32:Test3_1.08
Test1_2.12:Test2_5.12:Test3_2.13

We want to split on : and create rows (List of beans), then split on _ to create columns (properties on bean) and display this in a jr:table component.

java code (or Bean)
public class TableCellsBean {

    private String name;
    private double value;

    public TableCellsBean(String name,double value){
        this.name = name;
        this.value = value;
    }
    public static JRBeanCollectionDataSource getDatasource(String fieldValue){
        List<TableCellsBean> retList = new ArrayList<>();
        String[] values = fieldValue.split(":");
        for (String v : values) {
            String[] sp = v.split("_");
            retList.add(new TableCellsBean(sp[0], Double.parseDouble(sp[1])));
        }
        return new JRBeanCollectionDataSource(retList);
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public double getValue() {
        return value;
    }
    public void setValue(double value) {
        this.value = value;
    }
}

As you can see already inside this bean class I have added a static method that returns a JRBeanCollectionDataSource depending on value passed as parameter.

Basically you pass a fieldValue to this method, it does some logic, creates the TableCellBean, adds them to list and return a JRBeanCollectionDataSource

Note: The method does not need to be static nor inside this class, furthermore exception handling is not considered.

Report - the jrxml

In example we will have field1 containing Test1_1.23:Test2_4.32:Test3_1.08 on row 1 and Test1_2.12:Test2_5.12:Test3_2.13 on row 2.

We define a subdataset that represents out TableCellsBean

<subDataset name="table_dataset" uuid="4dc1b0fb-2588-4f98-8c8d-f0afefbb2fd1">
    <field name="name" class="java.lang.String"/>
    <field name="value" class="java.lang.Double"/>
 </subDataset>

as datasource we call our static method passing the field1 content in current row.

<dataSourceExpression><![CDATA[my.package.TableCellsBean.getDatasource($F{field1})]]></dataSourceExpression>

Full 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="test" language="java" pageWidth="595" pageHeight="842" columnWidth="555" leftMargin="20" rightMargin="20" topMargin="20" bottomMargin="20" uuid="886a547e-11bd-434b-a330-d93ee5e4a280">
    <style name="table">
        <box>
            <pen lineWidth="1.0" lineColor="#000000"/>
        </box>
    </style>
    <style name="table_TH" mode="Opaque" backcolor="#F0F8FF">
        <box>
            <pen lineWidth="0.5" lineColor="#000000"/>
        </box>
    </style>
    <style name="table_CH" mode="Opaque" backcolor="#BFE1FF">
        <box>
            <pen lineWidth="0.5" lineColor="#000000"/>
        </box>
    </style>
    <style name="table_TD" mode="Opaque" backcolor="#FFFFFF">
        <box>
            <pen lineWidth="0.5" lineColor="#000000"/>
        </box>
    </style>
    <subDataset name="table_dataset" uuid="4dc1b0fb-2588-4f98-8c8d-f0afefbb2fd1">
        <field name="name" class="java.lang.String"/>
        <field name="value" class="java.lang.Double"/>
    </subDataset>
    <field name="field1" class="java.lang.String">
        <fieldDescription><![CDATA[_THIS]]></fieldDescription>
    </field>
    <detail>
        <band height="40" splitType="Stretch">
            <textField>
                <reportElement x="0" y="0" width="555" height="20" uuid="a73343b1-ccb2-4a59-b882-381b98efd664"/>
                <textElement verticalAlignment="Middle"/>
                <textFieldExpression><![CDATA[$F{field1}]]></textFieldExpression>
            </textField>
            <componentElement>
                <reportElement key="table" style="table" x="0" y="20" width="555" height="20" uuid="09a9a5b8-499b-40d2-b391-ece25772a31e"/>
                <jr:table xmlns:jr="http://jasperreports.sourceforge.net/jasperreports/components" xsi:schemaLocation="http://jasperreports.sourceforge.net/jasperreports/components http://jasperreports.sourceforge.net/xsd/components.xsd">
                    <datasetRun subDataset="table_dataset" uuid="05601bdb-5579-4253-90f7-6742739d9714">
                        <dataSourceExpression><![CDATA[bounty.TableCellsBean.getDatasource($F{field1})]]></dataSourceExpression>
                    </datasetRun>
                    <jr:column width="90" uuid="afbbb3d0-573a-495d-ab51-0ae4d601e6fb">
                        <jr:tableHeader style="table_TH" height="20" rowSpan="1">
                            <staticText>
                                <reportElement x="0" y="0" width="90" height="20" uuid="e476f026-bbec-4b19-9bd4-f4b21f3377ef"/>
                                <textElement textAlignment="Center" verticalAlignment="Middle"/>
                                <text><![CDATA[Name]]></text>
                            </staticText>
                        </jr:tableHeader>
                        <jr:detailCell style="table_TD" height="20" rowSpan="1">
                            <textField>
                                <reportElement x="0" y="0" width="90" height="20" uuid="49cac181-b16b-4ab3-b600-78a56fb0f42b"/>
                                <box leftPadding="3" rightPadding="3"/>
                                <textElement verticalAlignment="Middle"/>
                                <textFieldExpression><![CDATA[$F{name}]]></textFieldExpression>
                            </textField>
                        </jr:detailCell>
                    </jr:column>
                    <jr:column width="90" uuid="4a1b0759-c347-4294-82c5-3aed4762f0c4">
                        <jr:tableHeader style="table_TH" height="20" rowSpan="1">
                            <staticText>
                                <reportElement x="0" y="0" width="90" height="20" uuid="bfa965b5-b5a4-484d-bfbd-d8bc753718b1"/>
                                <textElement textAlignment="Center" verticalAlignment="Middle"/>
                                <text><![CDATA[Value]]></text>
                            </staticText>
                        </jr:tableHeader>
                        <jr:detailCell style="table_TD" height="20" rowSpan="1">
                            <textField>
                                <reportElement x="0" y="0" width="90" height="20" uuid="925192bc-a761-48f5-bad5-097d15587198"/>
                                <box leftPadding="3" rightPadding="3"/>
                                <textElement textAlignment="Right" verticalAlignment="Middle"/>
                                <textFieldExpression><![CDATA[$F{value}]]></textFieldExpression>
                            </textField>
                        </jr:detailCell>
                    </jr:column>
                </jr:table>
            </componentElement>
        </band>
    </detail>
</jasperReport>

Test the example

Adding main method to export to pdf

public static void main(String[] args) throws JRException {
    //Compile report
    JasperReport report = JasperCompileManager.compileReport("myJasperReport.jrxml");
    //Setting up some arbitrary data to test the auto creation of datasource
    List<String> someData = new ArrayList<>();
    someData.add("Test1_1.23:Test2_4.32:Test3_1.08");
    someData.add("Test1_2.12:Test2_5.12:Test3_2.13");
    //Fill report
    JasperPrint jasperPrint = JasperFillManager.fillReport(report, new HashMap<>(),new JRBeanCollectionDataSource(someData));
    //Export to pdf
    JRPdfExporter exporter = new JRPdfExporter();       
    exporter.setExporterInput(new SimpleExporterInput(jasperPrint));
    exporter.setExporterOutput(new SimpleOutputStreamExporterOutput("myJasperReport.pdf"));
    SimplePdfExporterConfiguration configuration = new SimplePdfExporterConfiguration();
    exporter.setConfiguration(configuration);
    exporter.exportReport();
}
Output

Conclusion

The simplest way to provide components with custom datasource depending on running reports values (fields, variables, parameter), is to create a method that generates the datasource and call this in dataSourceExpression

Question:

I am trying to fill a table by passing a custom data source to it. I have created a simple report with a table on it. The report it self gets the data from a ms sql database. I have written a java class similar to the class in this Example. But I get no value in table. At the example there is no scriptlet. I have checked the (String) this.getFieldValue("KN_FormelGG"); line of code. It gets the data from field and can show it on report. So I guess the bean data source is not filled. I call the fill Table method in a afterGroupInit. How can I use Collection of data from java in jasper? I tried also adding the java bean in dataset and query dialog, but it did not help me either. Should I add the scriptlet to subreport/table? The main emphasis of my problem having the custom data source in a scriptlet. I went the other problem through, but I still get no answer. I added $P{FieldDataSource}.getData() to check the data, but it delivers null.

java class 1:

package testProjektIman.scriptlets;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import net.sf.jasperreports.engine.JRDefaultScriptlet;
import net.sf.jasperreports.engine.JRScriptletException;
import net.sf.jasperreports.engine.data.JRBeanCollectionDataSource;

public class FillTable extends JRDefaultScriptlet {

    @Override
public void afterGroupInit(final String id)
        throws JRScriptletException {
    fillTable();
}
public ArrayList<String> splitGGArray(final String kNFormelGG) {
    ArrayList<String> fieldNames = new ArrayList<>();
    String[] array = (kNFormelGG.split(" "));
    for (String sub : array) {
        fieldNames.add(sub);
    }
    return fieldNames;
}

public Map<String, Object> fillTable()
        throws JRScriptletException {
    String kNFormelGG = null;
    kNFormelGG = (String) this.getFieldValue("KN_FormelGG");
    List<TableCells> listTableCells = new ArrayList<>();
    TableCells tableCell;
    for (String fn : splitGGArray(kNFormelGG)) {
        tableCell = new TableCells();
        tableCell.setFieldName(fn);
        listTableCells.add(tableCell);
    }
    JRBeanCollectionDataSource tableCellJRBean = new JRBeanCollectionDataSource(listTableCells);
    Map<String, Object> parameters = new HashMap<>();
    parameters.put("FieldDataSource", tableCellJRBean);
    return parameters;
}

}

Java class 2

package testProjektIman.scriptlets;
public class TableCells {
private String fieldName;
private String keyFormel;
private String mK;
private String notation;
private String Item;
//getters setters
}

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="tableAutoFill" pageWidth="595" pageHeight="842" columnWidth="555" leftMargin="20" rightMargin="20" topMargin="20" bottomMargin="20" uuid="37fc3a9c-38e9-41be-9039-56249c5283d7">
    <subDataset name="TableDataSource" uuid="5999e646-aeec-4b2b-b29b-68e897d56999">
        <queryString>
            <![CDATA[]]>
        </queryString>
        <field name="fieldName" class="java.lang.String"/>
    </subDataset>
    <scriptlet name="Filltable" class="testProjektIman.scriptlets.FillTable"/>
    <parameter name="FieldDataSource" class="net.sf.jasperreports.engine.data.JRBeanCollectionDataSource" isForPrompting="false"/>
    <queryString>
        <![CDATA[select * from "KennzahlReferenz2015_QIBericht",  "Images" 
where LB_ID =  62
and KN_OffiziellGruppe =  3
and  IMG_ID = 1]]>
    </queryString>
    <field name="KN_Id" class="java.lang.Integer"/>
    <field name="KN_FormelZ" class="java.lang.String"/>
    <field name="KN_FormelGG" class="java.lang.String"/>
    <group name="id">
        <groupExpression><![CDATA[$F{KN_Id}]]></groupExpression>
        <groupHeader>
            <band height="50"/>
        </groupHeader>
        <groupFooter>
            <band height="50"/>
        </groupFooter>
    </group>
    <detail>
        <band height="191" splitType="Stretch">
            <componentElement>
                <reportElement x="50" y="18" width="260" height="120" uuid="942ab836-df83-4a2f-8215-845073ad163f">
                    <property name="com.jaspersoft.studio.layout" value="com.jaspersoft.studio.editor.layout.VerticalRowLayout"/>
                    <property name="com.jaspersoft.studio.table.style.table_header" value="Table_TH"/>
                    <property name="com.jaspersoft.studio.table.style.column_header" value="Table_CH"/>
                    <property name="com.jaspersoft.studio.table.style.detail" value="Table_TD"/>
                </reportElement>
                <jr:table xmlns:jr="http://jasperreports.sourceforge.net/jasperreports/components" xsi:schemaLocation="http://jasperreports.sourceforge.net/jasperreports/components http://jasperreports.sourceforge.net/xsd/components.xsd" whenNoDataType="AllSectionsNoDetail">
                    <datasetRun subDataset="TableDataSource" uuid="b554ada5-c388-4534-af8e-93571a417adb">
                        <parametersMapExpression><![CDATA[$P{FieldDataSource}]]></parametersMapExpression>
                        <dataSourceExpression><![CDATA[$P{FieldDataSource}]]></dataSourceExpression>
                    </datasetRun>
                    <jr:column width="100" uuid="f57e4e8e-8a2e-405f-b9ab-7a704e0986fd">
                        <property name="com.jaspersoft.studio.components.table.model.column.name" value="Column1"/>
                        <jr:columnHeader style="Table_CH" height="30">
                            <staticText>
                                <reportElement x="0" y="0" width="100" height="30" uuid="9a55dd73-71e3-4559-9a8b-17d98bf17753"/>
                                <textElement>
                                    <font isBold="true"/>
                                </textElement>
                                <text><![CDATA[FieldName]]></text>
                            </staticText>
                        </jr:columnHeader>
                        <jr:detailCell style="Table_TD" height="30">
                            <textField>
                                <reportElement x="0" y="0" width="100" height="30" uuid="c3e6ccfc-9f91-4d7a-800a-613f5dded928"/>
                                <textFieldExpression><![CDATA[$F{fieldName}]]></textFieldExpression>
                            </textField>
                        </jr:detailCell>
                    </jr:column>
                </jr:table>
            </componentElement>
        </band>
    </detail>
</jasperReport>

Answer:

Data Adapter

Create a data adapter file, for example adapter.xml, through the user interface. The contents might resemble:

<?xml version="1.0" encoding="UTF-8" ?>
<beanDataAdapter class="net.sf.jasperreports.data.bean.BeanDataAdapterImpl">
    <name>YourClass</name>
    <factoryClass>com.yourcompany.jasper.JRDataSourceFactory</factoryClass>
    <methodName>createCollection</methodName>
    <useFieldDescription>false</useFieldDescription>
</beanDataAdapter>
Data Class

Create a class that has a createCollection method, as per the data adapter definition above:

package com.compay.jasper;

public class JRDataSourceFactory {
    /**
     * @return A collection of data for the report.
     */
    public static Collection<YourClass> createCollection() {
        return Arrays.asList( new YourClass() );
    }
}
Set Report Properties

Ensure that the report has the following property (links the report to the custom data adapter):

<property name="com.jaspersoft.studio.data.defaultdataadapter" value="adapter.xml"/>
Set Report Fields

The report fields should now be able to reference the bean properties:

<field name="yourObject.property" class="java.lang.String">
    <fieldDescription><![CDATA[yourObject.property]]></fieldDescription>
</field>

It's important that the fieldDescription element contain a value that reflects the bean property (i.e., the Java code you would normally call to retrieve the value from the bean on an instance of that bean).

Application

The JRDataSourceFactory class stands alone -- it's used by the data adapter to create a collection of bean instances. The static method (createCollection) does the work here and does not, indeed cannot, use inheritance.

Example

If possible, borrow the field names for the report from the bean's attributes. The code as written in the question makes it difficult to discern where the value for KN_Id comes from.

The following example links the data adapter to the field names in the report.

Bean Class

A bean exposes some properties:

package com.company.domain;

public final class Student extends Entity {
    private String firstName;
    private String lastName;

    public String getFirstName() {
        return this.firstName;
    }

    public String getLastName() {
        return this.lastName;
    }
}
Data Adapter

The data adapter looks like:

<?xml version="1.0" encoding="UTF-8" ?>
<beanDataAdapter class="net.sf.jasperreports.data.bean.BeanDataAdapterImpl">
    <name>Student</name>
    <factoryClass>com.company.jasper.JRDataSourceFactory</factoryClass>
    <methodName>createCollection</methodName>
    <useFieldDescription>false</useFieldDescription>
</beanDataAdapter>
Data Class

The data class creates instances of the bean:

package com.compay.jasper;

import com.company.domain.Student;

public class JRDataSourceFactory {
    public static Collection<Student> createCollection() {
        return Arrays.asList( new Student() );
    }
}
Report Fields

The report fields reflect the bean fields:

<field name="firstName" class="java.lang.String">
    <fieldDescription><![CDATA[firstName]]></fieldDescription>
</field>
<field name="lastName" class="java.lang.String">
    <fieldDescription><![CDATA[lastName]]></fieldDescription>
</field>

A collection of "student" instances is passed into the report. In this example, the collection contains a single instance. In your example, the collection could contain many instances. As the report library iterates over the collection, different values of firstName and lastName will be made available.

The mechanics for how the Student instance data is initially populated is outside the scope of this answer. As far as the reporting tool is concerned, it simply uses pre-populated instances of Student. If FillTable populates TableCells, that's not a concern for the reporting tool.

Question:

Scenario:

I've two reports: Main Report (let's call it, A) and sub-report (let's call it, B).

Report A contains sub-report B at the detail band, so sub-report B is displayed for each element at the Report A datasource. Sub-report B also returns a variable to the Main report A.

What I want is to sum those return values from sub-report B and totalize them at the Main report summary.

To do that, I have tried to create a new report variable that sum those returns values... Something like this:

However, I've found that such variables expression are always evaluated before the band detail is rendered, so I always miss the first sub-report return value...

Sadly, the evaluation time (as this link says) cannot be changed on those kind of variables, so I'm stuck...


Answer:

After been struggling with this for some hours... and searching the internet for a solution... I came with a Workaround (the enlightening forums were these ones: one and two).

First, you need to define a java Class Helper that allows you calculate some arithmetic operation, in my case a Sum operation. I defined these classes:

package reports.utils;

import java.util.Map;

/**
 * Utility that allows you to sum Integer values.
 */
public class SumCalculator {

    /**
     * Stores a map of {@code SumCalculator} instances (A Map instance per thread).
     */
    private static final ThreadLocalMap<String, SumCalculator> calculatorsIndex = new ThreadLocalMap<>();

    /**
     * The sum total.
     */
    private int total = 0;


    /**
     * No arguments class constructor.
     */
    private SumCalculator() {
        super();
    }


    /**
     * Instance a new {@code SumCalculator} with the given ID.
     *
     * @param id    {@code SumCalculator}'s ID
     * @return      the new {@code SumCalculator} instance
     */
    public static SumCalculator get(String id) {
        Map<String, SumCalculator> map = calculatorsIndex.get();
        SumCalculator calculator       = map.get(id);

        if (calculator == null) {
            calculator = new SumCalculator();
            map.put(id, calculator);
        }
        return calculator;
    }


    /**
     * Destroy the {@code SumCalculator} associated to the given ID.
     *
     * @param id    {@code SumCalculator}'s ID
     * @return      {@code null}
     */
    public static String destroy(String id) {
        Map<String, SumCalculator> map;

        map = calculatorsIndex.get();
        map.remove(id);

        if (map.isEmpty()) {
            calculatorsIndex.remove();
        }
        return null;
    }


    /**
     * Resets the {@code SumCalculator} total.
     *
     * @return  {@code null}
     */
    public String reset() {
        total = 0;
        return null;
    }


    /**
     * Adds the given integer value to the accumulated total.
     *
     * @param i     an integer value (can be null)
     * @return      {@code null}
     */
    public String add(Integer i) {
        this.total += (i != null) ? i.intValue() : 0;
        return null;
    }


    /**
     * Return the accumulated total.
     *
     * @return  an Integer value (won't be null, never!)
     */
    public Integer getTotal() {
        return this.total;
    }
}

Question:

I created a report using JasperSoft Studio.

I'm referencing to this helpful post Jaspersoft Studio: How to use Collection of Java Beans in data adapter by Alex K

I'd like to retrieve a list of orders. The class Order is defined as in the post:

public class Order {
    private double price;
    private int quantity;
    private Product product;

    // Getters & Setters
}

The report is generated with success if I'd like to retrieve price or quantity. But, once I retrieve product this is displayed:

Details:

net.sf.jasperreports.engine.fill.JRExpressionEvalException: Error evaluating expression for source text: $F{product}.getName()
    at com.jaspersoft.studio.editor.preview.view.control.ReportControler.fillReport(ReportControler.java:530)
    at com.jaspersoft.studio.editor.preview.view.control.ReportControler.access$20(ReportControler.java:505)
...
Caused by: java.lang.ClassCastException: ru.alex.Product cannot be cast to ru.alex.Product
    at net.sf.jasperreports.engine.fill.JREvaluator.evaluate(JREvaluator.java:277)
    ... 14 more

The file sample.jrxml was:

<?xml version="1.0" encoding="UTF-8"?>
<!-- Created with Jaspersoft Studio version 6.3.1.final using JasperReports Library version 6.3.1  -->
<!-- 2017-05-18T13:29:14 -->
<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="sample" pageWidth="595" pageHeight="842" columnWidth="555" leftMargin="20" rightMargin="20" topMargin="20" bottomMargin="20" uuid="ade9e357-e2d0-42bb-ae0d-000b69f4e2e9">
    <property name="com.jaspersoft.studio.data.defaultdataadapter" value="JavaBeanCollection - orders"/>
    <queryString>
        <![CDATA[]]>
    </queryString>
    <field name="product" class="ru.alex.Product">
        <fieldDescription><![CDATA[product]]></fieldDescription>
    </field>
    <field name="quantity" class="java.lang.Integer">
        <fieldDescription><![CDATA[quantity]]></fieldDescription>
    </field>
    <field name="price" class="java.lang.Double">
        <fieldDescription><![CDATA[price]]></fieldDescription>
    </field>
    <title>
        <band height="80" splitType="Stretch">
            <staticText>
                <reportElement x="70" y="49" width="100" height="30" uuid="a19f5b7c-21ed-4c00-a224-af5cf7ef27ec"/>
                <text><![CDATA[price]]></text>
            </staticText>
            <staticText>
                <reportElement x="170" y="49" width="100" height="30" uuid="772c4807-25f7-4e7a-8a10-eba5232b92c7"/>
                <text><![CDATA[quantity]]></text>
            </staticText>
            <staticText>
                <reportElement x="270" y="49" width="140" height="30" uuid="613da9ef-6a5a-45b2-8c8f-c3cd450e66ed"/>
                <text><![CDATA[product]]></text>
            </staticText>
        </band>
    </title>
    <detail>
        <band height="130" splitType="Stretch">
            <textField>
                <reportElement x="70" y="0" width="100" height="30" uuid="a594224b-c015-4dab-b52b-6e317e76cea3"/>
                <textFieldExpression><![CDATA[$F{price}]]></textFieldExpression>
            </textField>
            <textField>
                <reportElement x="170" y="0" width="100" height="30" uuid="b60503ca-f6bc-48dc-ad01-178d9befd805"/>
                <textFieldExpression><![CDATA[$F{quantity}]]></textFieldExpression>
            </textField>
            <textField>
                <reportElement x="270" y="0" width="140" height="30" uuid="480bfb2f-2831-4700-8adc-f818bbbf6592"/>
                <textFieldExpression><![CDATA[$F{product}.getName()]]></textFieldExpression>
            </textField>
        </band>
    </detail>
</jasperReport>

The JRBeanCollection is the following:

public class MyImplementation implements JRDataSource {
    // (...)
    public static Collection<Order> getOrders() {
        List<Order> orders = new ArrayList<Order>();
        orders.add(new Order(1, "aa", new BigDecimal("1111.11"), 2, new Product("apples")));
        orders.add(new Order(2, "bb", new BigDecimal("2222.22"), 10, new Product("oranges")));

        return orders;
        }
    // (...)
}

Could you please tell me what is the reason for the exception?


Answer:

It looks like a bug of Jaspersoft Studio (JSS).

I think that the reason of getting ClassCastException (look at this part of stacktrace: Caused by: java.lang.ClassCastException: ru.alex.Product cannot be cast to ru.alex.Product) is using of two jar files:

  • the first jar was set for a data provider;
  • second one - via project's build path.

Yes, it is the same jar file (physically) with the same classes. Looks like the issue of having multiple jar at classpath.

After understanding the root of the problem we can fix this issue very easy.

We should stay only one jar with our bean classes - at JSS build path:

It means that we should remove the jar from data adapter's properties. Like this:

After this it is better to restart JSS.

For this 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="Report with Bean" pageWidth="595" pageHeight="842" columnWidth="555" leftMargin="20" rightMargin="20" topMargin="20" bottomMargin="20">
    <property name="com.jaspersoft.studio.data.defaultdataadapter" value="JavaBeanCollection - orders"/>
    <field name="product" class="ru.alex.Product">
        <fieldDescription><![CDATA[product]]></fieldDescription>
    </field>
    <field name="quantity" class="java.lang.Integer">
        <fieldDescription><![CDATA[quantity]]></fieldDescription>
    </field>
    <field name="price" class="java.lang.Double">
        <fieldDescription><![CDATA[price]]></fieldDescription>
    </field>
    <detail>
        <band height="30" splitType="Stretch">
            <textField>
                <reportElement x="10" y="0" width="100" height="30"/>
                <textFieldExpression><![CDATA[$F{quantity}]]></textFieldExpression>
            </textField>
            <textField>
                <reportElement x="110" y="0" width="100" height="30"/>
                <textFieldExpression><![CDATA[$F{price}]]></textFieldExpression>
            </textField>
            <textField>
                <reportElement x="210" y="0" width="100" height="30"/>
                <textFieldExpression><![CDATA[$F{product}.getName()]]></textFieldExpression>
            </textField>
        </band>
    </detail>
</jasperReport>

we are getting report at JSS successfully:


Everything working fine (without any black magic) at Java project, because we have only single jar with our bean classes at classpath.

Question:

In Jasper Studio 6.6.0, you can configure the connection to the database and start using the data from there. When I finished the report in the studio, I took the jrxml-file and then used it in the project to print pdf-reports.

Does the jrxml-markup store information about the connection to the database that was used in the studio?

P.S. I've not found such information inside jrxml. Well, now it's not clear: why connection to a DB is implemented in Jasper Studio and demonstration of filling the report with data from there?


Answer:

As I found out later - the jrxml-markup only stores label that data should be taken from the database via connection. So when the function of forming the JasperPrint invoked you can pass the java.sql.Connection object as the last parameter:

JasperFillManager.fillReport(JasperReport jReport, Map<String,Object> params, Connection connection)

And the data will be received from the database.