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.

9 comments:

  1. Thanks a lot... I was struggling to create subreports using java bean. This might help me. I will definitely try this method.
    Thank U once again

    ReplyDelete
  2. Thanks a lot... I was struggling to create subreports using java bean. This might help me. I will definitely try this method.
    Thank U once again

    ReplyDelete
  3. Thanks for putting this example together, very clear and concise.

    ReplyDelete
  4. Replies
    1. Now I use 1.7, but this sample can use 1.6.

      Delete
  5. Hi , Can't we avoid creating a subreport ? can we use variable or parameter instead ?

    ReplyDelete
  6. 1) Goal of this article is working with subreports.
    2) Yes, you can use variables and parameters. See some samples in neighboring articles.

    ReplyDelete
  7. Can you show, How JRBeanDataSourceCollection you are passing from Java program?
    I mean to ask, what do you pass a parameter ?

    ReplyDelete
  8. hi team..
    Can any of you help me in printing the page numbers in sub report..?

    At present i am finding difficulties in printing the page numbers at the bottom of each page..I am having more than 35 tables in the document and each tables I created as Subreport with one master report..

    I am able to generate the pdf, but when trying to print the page numbers, each subreports are displaying in new page and page numbers were displayed accordingly.

    My requirement is that the report should display in sequence as like generic document with page number..

    ReplyDelete