Monday, September 8, 2014

Runing JasperReport subreport from java code

In previous post I created JasperReport report with subreport and runned it from through iReport. But, I think, more interesting is way to run it from java code.


Preparing to work.

Because JasperReport has lot of dependencies I use maven for
satisfy it and for building runnable jar. If you never used maven then can read this short and easy tutorial. If you not worry about dependencies and build tools you can skip prepare part and go to main part. Otherwise, you can create initial maven project with next command:


mvn archetype:create -DarchetypeGroupId=org.apache.maven.archetypes -DgroupId=com.blogspot.mkazarian -DartifactId=ireport-experiments
Result of command will creating new file objects:

.
└── ireport-experiments
    ├── pom.xml
    └── src
        ├── main
        │   └── java
        │       └── com
        │           └── blogspot
        │               └── mkazarian
        │                   └── App.java
        └── test
            └── java
                └── com
                    └── blogspot
                        └── mkazarian
                            └── AppTest.java

12 directories, 3 files
Rename App.java to Demo.java and AppTest.java to DemoTest.java and change pom.xml as bellow:
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
  <modelVersion>4.0.0</modelVersion>
  <groupId>com.blogspot.mkazarian</groupId>
  <artifactId>ireport-experiments</artifactId>
  <packaging>jar</packaging>
  <version>1.0-SNAPSHOT</version>
  <name>ireport-experiments</name>
  <url>http://maven.apache.org</url>
  <build>
    <plugins>
      <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-compiler-plugin</artifactId>
        <version>3.1</version>
        <configuration>
          <source>1.6</source>
          <target>1.6</target>
         </configuration>
      </plugin>
      <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-jar-plugin</artifactId>
        <version>2.5</version>
        <configuration>
          <archive>
            <manifest>
              <mainClass>com.blogspot.mkazarian.Demo</mainClass>
            </manifest>
          </archive>
        </configuration>
      </plugin>
      <plugin>
        <groupId>org.codehaus.mojo</groupId>
        <artifactId>exec-maven-plugin</artifactId>
        <version>1.3.2</version>
        <configuration>
          <mainClass>com.blogspot.mkazarian.Demo</mainClass>
          <executable>java</executable>
          <arguments>
            <argument>-a</argument>
            <argument>${argumentA}</argument>
            <argument>-b</argument>
            <argument>${argumentB}</argument>
          </arguments>
        </configuration>
      </plugin>
      <plugin>
     <groupId>org.apache.maven.plugins</groupId>
     <artifactId>maven-clean-plugin</artifactId>
     <version>2.5</version>
      <configuration>
        <filesets>
          <fileset>
            <directory>reports</directory>
            <includes>
              <directory>jaspers</directory>
              <include>**/*.pdf</include>
              <include>**/*.jasper</include>
            </includes>
            <excludes>
              <exclude>**/*.jrxml</exclude>
            </excludes>
            <followSymlinks>false</followSymlinks>
          </fileset>
        </filesets>
      </configuration>
    </plugin>
    </plugins>
  </build>
  <dependencies>
    <dependency>
      <groupId>junit</groupId>
      <artifactId>junit</artifactId>
      <version>3.8.1</version>
      <scope>test</scope>
    </dependency>
    <dependency>
      <groupId>net.sf.jasperreports</groupId>
      <artifactId>jasperreports</artifactId>
      <version>5.6.0</version>
    </dependency>
    <dependency>
     <groupId>org.codehaus.groovy</groupId>
     <artifactId>groovy-all</artifactId>
     <version>2.3.6</version>
    </dependency>
  </dependencies>
</project>
Execute  mvn compile command and mvn exec:java for test.

Running reports from java.

Add OrderBean.java, OrderDetailBean.java and OrderFactory.java from this article beside Demo.java. Create reports directory with java_beans_datasource_report.jrxml and java_beans_datasource_report_subreport1.jrxml . In result must view similat this:

.
├── pom.xml
├── reports
│   ├── java_beans_datasource_report.jrxml
│   └── java_beans_datasource_report_subreport1.jrxml
└── src
    ├── main
    │   └── java
    │       └── com
    │           └── blogspot
    │               └── mkazarian
    │                   ├── Demo.java
    │                   ├── OrderBean.java
    │                   ├── OrderDetailBean.java
    │                   └── OrderFactory.java
    └── test
        └── java

Ok, now we can write our code. Change Demo.java:

package com.blogspot.mkazarian;

/**
 * Subreporting demo. It compile jrxml to jasper-files and pass it to
 * generate report.
 */
import java.io.File;
import java.io.FileInputStream;
import java.util.HashMap;
import java.util.List;

import net.sf.jasperreports.engine.JRException;
import net.sf.jasperreports.engine.JasperCompileManager;
import net.sf.jasperreports.engine.JasperFillManager;
import net.sf.jasperreports.engine.JasperPrint;
import net.sf.jasperreports.engine.JasperReport;
import net.sf.jasperreports.engine.data.JRBeanCollectionDataSource;
import net.sf.jasperreports.view.JasperViewer;

public class Demo
{
    public static JasperPrint jasperPrint;
    public static JasperReport mainReport;

    final static String reportsDirName = System.getProperty("user.dir")+"/reports";
    final static String jasperDirName = "/jaspers";
    final static String [] jrxmlFiles = {"java_beans_datasource_report",
                                         "java_beans_datasource_report_subreport1"};

    public static String getJasperDir(String jrxmldir){
        /**
         * Retutn directory for compiled report. Normally it jaspers directory
         * into reports directory. If jasper directoty missing it will create.
         */
        String result = System.getProperty("user.home");
        File jrxmlDir = new File(jrxmldir);
        File jasperDir = new File(jrxmldir + jasperDirName);
        if (jrxmlDir.exists() && jrxmlDir.isDirectory()){
            boolean cdres = true;
            if (!jasperDir.exists()) {
                cdres = false;
                try {
                    jasperDir.mkdir();
                    cdres = true;
                } catch(SecurityException se){}
            }
            if (cdres) result = jrxmldir + jasperDirName;
        }
        return result;
    }
    public static boolean compileJRXML(){
        /**
         *  Compile all jrxml from reports to jasper and pur it to getJasperDir result.
         */
        boolean result = false;
        String jdn = getJasperDir(reportsDirName);
        String s, o;
        File outf;
        try{
            for (String rep: jrxmlFiles){
                s = reportsDirName+"/"+rep+".jrxml";
                o = jdn+"/"+rep+".jasper";
                JasperCompileManager.compileReportToFile(s, o);
                outf = new File(o);
                if (!outf.exists()) return false;
            }
        } catch (JRException e) {return false;}
        result = true;
        return result;
    }
    public static void main( String[] args ){
        try{
            //Parameters for pass to report
            HashMap<String,Object> parameters = new HashMap<String,Object>();
            //Organize datasource
            OrderFactory of = new OrderFactory();
            List<OrderBean> dataSource = of.create(); 
            JRBeanCollectionDataSource beanDataSource = new JRBeanCollectionDataSource(dataSource);
            //Compile jrxml to jasper-files.
            FileInputStream mainReportFile = null;
            if (compileJRXML()){
            //If you haven't plans to compile jrxml scip this call. Alternate
            //way to create a mainReportFile
            //import net.sf.jasperreports.engine.design.JasperDesign mainDesign = JRXmlLoader.load("/path/to/jrxml");
            //JasperReport mainReportFile = JasperCompileManager.compileReport(mainDesign);
                try{
                    String s = getJasperDir(reportsDirName)+"/"+jrxmlFiles[0]+".jasper";
                    mainReportFile = new FileInputStream(s);
                    //pass directory with jasper-files as parameters
                    parameters.put("SUBREPORT_DIR", getJasperDir(reportsDirName)+"/");
                    //Fill report and view report.
                    jasperPrint = JasperFillManager.fillReport(mainReportFile, parameters, beanDataSource);
                    JasperViewer.viewReport(jasperPrint);
                } catch (Exception fise){fise.printStackTrace();}
                finally {
                    if (mainReportFile != null) mainReportFile.close();
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}  
Go to root directory and compile project with mvn compile and run it with mvn exec:java commands.

Related posts:

Using JavaBean datasource for report and subreport in iReport

JasperReport and Maven for creating distributive

Downloads:

Source code (java and jrxms) on BitBucket.