Wednesday, August 6, 2014

Using JavaBean datasource for report and subreport in iReport

Usually I prefer use pure SQL as datasource for various database-related tasks, e.g. reporting. But for some tasks is better way to use JavaBean as datasource model. Below I will write sample such datasource and reveal how use it for obtain such result.
Picture 1: Report, based on JavaBean datasource.

Create JavaBean datasource.

Below we will simulate master and detail tables. For master table we will use model of order documents;  for detail table we will use model of records, related with master. And, at last, we will incorporate these models in factory which return data for iReport.

/**
 * OrderBean.java. Created Tuesday, August 5 2014
 * @author Michael Kazarian
 * Tags:
 */
package com.blogspot.mkazarian;

import java.util.Date;
import java.util.List;

public class OrderBean{
    /**
     *This class describes master records.
     */
    private String nDoc; //Document number
    private Date date; //Document date
    private List<OrderDetailBean> orderDetails;

    public Date getDate() {
        return date;
    }
    public void setDate(Date date) {
        this.date = date;
    }
    public String getNDoc() {
        return nDoc;
    }
    public void setNDoc(String nDoc) {
        this.nDoc = nDoc;
    }
    public List<OrderDetailBean> getOrderDetails() {
        return orderDetails;
    }
    public void setOrderDetails(List<OrderDetailBean> orderDetails) {
        this.orderDetails = orderDetails;
    }
}
//File: OrderBean.java ends here.


/**
 * OrderDetailBean.java. Created Tuesday, August 5 2014
 * @author Michael Kazarian
 * Tags:
 */
package com.blogspot.mkazarian;

public class OrderDetailBean{
    /**
     * This class describes detail records for OrderBean.
     */
    private String name;
    private int quantity;
    private Double price;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getQuantity() {
        return quantity;
    }

    public void setQuantity(int quantity) {
        this.quantity = quantity;
    }
    
    public Double getPrice() {
        return price;
    }

    public void setPrice(Double price) {
        this.price = price;
    }

}
//File: OrderDetailBean.java ends here.


/**
 * OrderFactory.java. Created Tuesday, August 5 2014
 * @author Michael Kazarian
 * Tags:
 */
package com.blogspot.mkazarian;

import java.util.List;
import java.util.Arrays;
import java.text.SimpleDateFormat;
import java.text.ParseException;
import java.util.Date;


public class OrderFactory{
    /**
     * This class incorporate master and detail records.
     * For master records used OrderBean class; OrderDetailBean for detail record.
     */
    public static List<OrderBean> create(){
        /**
         * Factory-method for get datasource.
         */
        //Add two master records
        OrderBean order1 = new OrderBean(); 
        order1.setNDoc("1");
        OrderBean order2 = new OrderBean();
        order2.setNDoc("2");
        //Set Date format
        SimpleDateFormat textDate = new SimpleDateFormat("dd.MM.yyyy");
        try{
            order1.setDate(textDate.parse("05.08.2014"));
            order2.setDate(textDate.parse("10.08.2014"));
        } catch (ParseException pe){
            order1.setDate(new Date());
            order2.setDate(new Date());
        }
        //Detail records for master record 1
        OrderDetailBean detail1 = new OrderDetailBean();
        detail1.setName("Position one for document1");
        detail1.setQuantity(10);
        detail1.setPrice(123.45);
        OrderDetailBean detail2 = new OrderDetailBean();
        detail2.setName("Position two for document1");
        detail2.setQuantity(7);
        detail2.setPrice(23.52);
        //Detail records for master record 2
        OrderDetailBean detail3 = new OrderDetailBean();
        detail3.setName("Position one for document2");
        detail3.setQuantity(76);
        detail3.setPrice(0.34);
        OrderDetailBean detail4 = new OrderDetailBean();
        detail4.setName("Position two for document2");
        detail4.setQuantity(22);
        detail4.setPrice(1.12);
        //Add detail records
        order1.setOrderDetails(Arrays.asList(detail1, detail2));
        order2.setOrderDetails(Arrays.asList(detail3, detail4));
        return Arrays.asList(order1, order2);
    }
}
//File: OrderFactory.java ends here.
I advice create jar file for have our datasource as one file . Also you can download my jar-file.

Creating main reports.

Before creating reports we must register our datasource. It include two clauses:
  • Add datasource to CLASSPATH. In iReport case open "Tools/Options" and add class or jar files in appropriate place.
Picture 2: Set CLASSPATH
  •  For register datasource press Report Datasourced button. Next press New button and select JavaBeans set datasource item. In next window fill all fields as on the picture:
Picture 3: Set datasource properties
  •  Now we can create report. In new report disable all bands except Detail and save as java_beans_datasource_report.jrxml.
  • Next we must register our datafields. Call "Edit query" and fill parameters as on the picture:
Picture 4: Set datafields
  • Add Ndoc and Date fields on Detail band:
Picture 5: Adding fields on main report
If you did everything correctly you can see next result:
Picture 6: Our first result.

Creating subreport.

Add subreport component from Pallete and save it as java_beans_datasource_report_subreport1.jrxml. Next, call edit query and fill parameters as on the picture:
Picture 6: Set datafields for subreport.
 In subreport disable all bands except Detail and Title. For me it looks like below:
Picture 7: Mastering subreport.
Now need tune subreport datasource. Switch to main (master) report and select Subreport component on Detail band. Set subreport properties:
  1. Expression class to java.util.List
  2. Connection type to Use datasource expression
  3. Subreport Expression to
    $P{SUBREPORT_DIR} + "java_beans_datasource_report_subreport1.jasper"
    
  4. Data source expression to
    new net.sf.jasperreports.engine.data.JRBeanCollectionDataSource($F{orderDetails})
    
     
    Picture 8: Tune subreport datasource.
Last step it save and compile subreport and main report. Press Preview button and enjoy result from Picture1.

Downloads:
  1. jar-file with JavaBean datasource.
  2. Master report java_beans_datasource_report.jrxml Note: perhaps you need to change Default Value Expression of  SUBREPORT_DIR parameter to other, than "./". Set it corresponding to directory what contains jrxml files.
  3. Subreport java_beans_datasource_report_subreport1.jrxml
  4. Source code (include all jar, java and jrxml files).
  5. Source code from  BitBucket repository.

Related  articles:

 Credits:

  • Richard Nichols for idea 
  • Sandeep Ujjwal for solutions of connect to JavaBean datasource in his article.
  • David Hamilton for answer about subreport datasource.