Search code examples
javajasper-reportsexport-to-excel

How to create Excel report with subtable with Jasper reports


I am using Jasper reports to create Excel file programmatically. I am using Java Data Source - a java class that implements JRDataSource interface. Up until now My Datasource returned a List of class instances that looked something like this:

public Class MyDataSource implements JRDataSource {
  private Integer prop1;
  private String prop2;
  private String prop3;
  ...
  // getters and setters omitted to save space
}

With this Data Source I was able to create a very nice excel table that looked:

prop1-Header prop2-Header prop3-Header...
----------------------------------------
prop1-value  prop2-value  prop3-value...
prop1-value  prop2-value  prop3-value...
...

But now MyDataSource class has additional property List<String>

public Class MyDataSource implements JRDataSource {
  private Integer prop1;
  private String prop2;
  private String prop3;
  private List<String> subvalues;
  ...
  // getters and setters omitted to save space
}

So I need my excel to look like this

prop1-Header prop2-Header prop3-Header...
----------------------------------------
prop1-value  prop2-value  prop3-value...
                                         Sub-header1 Sub-header2...
                                         -----------------------
                                         sub-value1  sub-value2....
                                         ....
prop1-value  prop2-value  prop3-value...
                                         Sub-header1 Sub-header2...
                                         -----------------------
                                         sub-value1  sub-value2....
                                         ....
...

I managed to do that by concatenating The list into a single string, and it looks very similar to what I need. But I have no way of sorting and filtering on sub-value data. So, I need to actually make it as sub-list or sub-table. And this is my question - how to do this?


Solution

  • After searching for a while I found the solution. First of all, the is a very nice youtube video

    How to fill Jasper Report Table using Collection of data in Java?

    This video shows in greate detail how to pass from java code into report an additional collection besides your Datasource java class. This is done by doing something like this:

        JRBeanCollectionDataSource detailBean = new JRBeanCollectionDataSource(getMySubvaluesINstancesList());
        Map<String, Object> params = new HashMap<>();
        params.put("DetailDataSource", detailBean);
        jasperPrint = JasperFillManager.fillReport(jasperReport, params, ds);
    


    Note the name "DetailDataSource". In your report, you will need to create a parameter with that name and declare it's type as net.sf.jasperreports.engine.data.JRBeanCollectionDataSource. After that, you build a table based on a dataset that you create based on that parameter. But this is a short description of the video referenced above.

    However, that alone doesn't solve the problem yet. The remaining problem that collection passed as a parameter will only be rendered once and will not be rendered for each record of your datasource. So, what we need to do is to add our list property into our datasource class, the same way as described in the question:

    public Class MyDataSource implements JRDataSource {
      private Integer prop1;
      private String prop2;
      private String prop3;
      private List<String> subvalues;
      ...
      // getters and setters omitted to save space
    }
    


    After that in your report you will need to declare a field named "subvalues" and declare its type as java.util.List. And then change the definition of your Dataset that you created following the video referenced above. You will need to change JRDatasource expression from $P{yourParameterName} to new net.sf.jasperreports.engine.data.JRBeanCollectionDataSource($F{subvalues}) And bingo! your collection is part of a datasource and will be rendered for each record