3

Suppose I have 2 beans:

  • Award
  • Employee

I add both of them in a collection. Based on this collection I want to generate a report using DynamicJasper using JRBeanCollectionDataSource.

I'm able to generate the report for a single bean, but for collection of different bean I cant create a report - I get an error.

Is it possible to create a report for two different beans at a time?

Are there any alternative solution to solve this task?

Alex K
  • 22,315
  • 19
  • 108
  • 236
Chetan Pulate
  • 503
  • 1
  • 7
  • 21

2 Answers2

1

With the information given, it implies there is no relationship between Award and Employee. If that is the case you could create a Custom Data Source to handle this for you. For the sake of completeness I am going to include a stubbed out Award, and Employee class along with a custom Data Source called MixedDataSource. (There is going to be a lot code listed here, but stick with me for a second).

Award.java

package test;

public class Award {

    private String shortName;

    private String description;

    public Award(String shortName, String description) {
        super();
        this.shortName = shortName;
        this.description = description;
    }

    public String getShortName() {
        return shortName;
    }

    public void setShortName(String shortName) {
        this.shortName = shortName;
    }

    public String getDescription() {
        return description;
    }

    public void setDescription(String description) {
        this.description = description;
    }
}

Employee.java

package test;

public class Employee {

    private String name;

    private String position;

    public Employee(String name, String position) {
        super();
        this.name = name;
        this.position = position;
    }

    public String getName() {
        return name;
    }

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

    public String getPosition() {
        return position;
    }

    public void setPosition(String position) {
        this.position = position;
    }

}

MixedDataSource.java

package test;

import java.util.List;

import net.sf.jasperreports.engine.JRDataSource;
import net.sf.jasperreports.engine.JRException;
import net.sf.jasperreports.engine.JRField;

@SuppressWarnings("rawtypes")//have to add this because we are not using generics
public class MixedDataSource implements JRDataSource {

    private List rows;
    private int index=0;

    public MixedDataSource(List rows) {
        super();
        this.rows = rows;
    }

    @Override
    public Object getFieldValue(JRField arg0) throws JRException {
        Object obj = rows.get(index);
        if (obj instanceof Award){
            Award row = (Award)obj;
            //now get the field name
            if (arg0.getName().equals("shortName")){
                return row.getShortName();
            } else if(arg0.getName().equals("description")){
                return row.getDescription();
            }
        } else if (obj instanceof Employee){
            Employee row = (Employee)obj;
            if (arg0.getName().equals("name")){
                return row.getName();
            } else if(arg0.getName().equals("position")){
                return row.getPosition();
            }
        }
        //means we don't know what to do with it, so just return null
        return null;
    }

    @Override
    public boolean next() throws JRException {
        //This method is used by jasper to tell us they are moving to the next row.
        //So increment the index and return true if there are still more rows, if not
        //return false
        index = index+1;
        if(index < rows.size()){
            return true;
        }
        return false;
    }

}

This would work, but probably not the way you want. My assumption is that there is a relationship between an Award and Employee and you are wanting to do some type of grouping and ordering. Essentially you want an Award and Employee on the same row. You may want to group by Award and list the Employees. You may want to do the opposite and group by Employee and list Awards. If that is the case, ignore all that above, it is useless.

What you really need to do is create a new bean (we could call it EmployeeAward) with the information you have. This could be really easy, if you are using a sql query to do this, or may require a little more work if you are using something like hibernate. where you are essentially just saying give all the Awards and it gives you a list. If you are doing the latter, it will probably be easier to step down to SQL or HSQL(I think that what they call it) and write the query by hand.

So create a class called EmployeeAward. Here is mine: package test;

public class EmployeeAward {


    private String employeeName;

    private String employeePosition;

    private String shortName;

    private String description;

    public EmployeeAward(String employeeName, String employeePosition,
            String shortName, String description) {
        super();
        this.employeeName = employeeName;
        this.employeePosition = employeePosition;
        this.shortName = shortName;
        this.description = description;
    }

    public EmployeeAward(Employee employee, Award award) {
        super();
        this.employeeName = employee.getName();
        this.employeePosition = employee.getPosition();
        this.shortName = award.getShortName();
        this.description = award.getDescription();
    }

    public String getEmployeeName() {
        return employeeName;
    }

    public void setEmployeeName(String employeeName) {
        this.employeeName = employeeName;
    }

    public String getEmployeePosition() {
        return employeePosition;
    }

    public void setEmployeePosition(String employeePosition) {
        this.employeePosition = employeePosition;
    }

    public String getShortName() {
        return shortName;
    }

    public void setShortName(String shortName) {
        this.shortName = shortName;
    }

    public String getDescription() {
        return description;
    }

    public void setDescription(String description) {
        this.description = description;
    }


}

Now by whatever means you have create your list of these object so you have a List<EmployeeAward> emplyeeAwards instantiated in there. Each item in this list is going to be a row in your report. Now here is the nice part, create your dataSource:

JRDataSource datasource = new JRBeanCollectionDataSource(employeeAwards);

Then pass that on like normal and your work is done.

In closing, I would like to say you can do a lot of cool things with JasperReports, but what I see a lot of folks doing is making it more complicated than it needs to be. You will find that JasperReports like what I call flat datasources (i.e. same objects in list, each item in list is a row, etc). If you do that, life becomes easier and more enjoyable.

Jacob Schoen
  • 14,034
  • 15
  • 82
  • 102
  • jschoen thank you for u r reply buddy it was really appreciable of u to try solve my problem u guessed right Employee has a many to many relationship with award .so employee has a collection of award in it. – Chetan Pulate Aug 25 '12 at 08:26
  • so while displaying employee i was expecting that dynamic jasper will also display the collection of award also but i guess it wont. i am trying to solve it using sql query hope it works – Chetan Pulate Aug 25 '12 at 08:28
0

An alternative for this can be use an SubReport and pass the List<Award> to the MainReport and the List<Employee> to the SubReport, doing that, you can set your SubReport as an extension of your MainReport, example:

MainReport: |FieldAward1|FieldAward2|FieldAward3|...|YOUR SUBREPORT HERE|

SubReport: |FieldEmployee1|FieldEmployee3|FieldEmployee3|...

Edit: Even if it seems basic, I have to tell you that you should sort your list in a way to make each Object inside one list matches with its repective Object inside the another one.

Diego Urenia
  • 1,620
  • 2
  • 21
  • 28