Moazzam
Moazzam

Reputation: 429

How to create a drill-down report called from Java?

I have created Balances report using Jaspersoft Studio. I have also created hyperlink on a field in this report with below properties:

Link Type: ReportExecution
Parameters: _report

The value of above parameter is "GLLedger" which is another jasper report present in the same folder.

In Java, when I invoke this report, and click the hyperlink, then GLLedger report does not appear but get below warning on console:

Hyperlink of type ReportExecution
Implement your own JRHyperlinkListener to manage this type of event.

In Java, I am using JasperViewer to preview report. Below is the code:

JasperPrint jasperPrint = JasperFillManager.fillReport(reportPath, hm, connection);
JasperViewer v = new JasperViewer(jasperPrint, false);
v.setVisible(true);

Can you please guide as how to call another report from one jasper report?

Upvotes: 2

Views: 1370

Answers (1)

Petter Friberg
Petter Friberg

Reputation: 21710

If you like to use this in a swing application your main problem (at least in jasper report version <6.1.1) is that you have no direct method to add a JRHyperLinkListener

From source code of JRViewer:

//FIXME add a method to do addHyperlinkListener without subclassing
protected JRViewerPanel createViewerPanel(){return new JRViewerPanel(viewerContext);}

I will show you a way how you can subclass this class, implement the JRHyperlinkListener and open a new frame with a report name received from link.

Java code

Creating a class that extends the net.sf.jasperreports.swing.JRViewer and implements the net.sf.jasperreports.view.JRHyperlinkListener, I'm adding imports since library have old classes with same name,

import java.awt.BorderLayout;
import java.util.HashMap;
import javax.swing.JFrame;
import net.sf.jasperreports.engine.JRException;
import net.sf.jasperreports.engine.JRPrintHyperlink;
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.swing.JRViewer;
import net.sf.jasperreports.swing.JRViewerPanel;
import net.sf.jasperreports.view.JRHyperlinkListener;

public class HyperLinkTest extends JRViewer implements JRHyperlinkListener {

    private static final long serialVersionUID = -6429615130889276357L;

    public HyperLinkTest(JasperPrint jrPrint){
        super(jrPrint);
    }

    /**
     * Since JRViewerPanel is protected our only way to add listener is
     * to Override
     */
    @Override
    protected JRViewerPanel createViewerPanel()
    {
        JRViewerPanel panel =  new JRViewerPanel(viewerContext);
        panel.addHyperlinkListener(this);
        return panel;
    }

    /**
     * The listener gets the hyperlink reference and open relative report
     */
    @Override
    public void gotoHyperlink(JRPrintHyperlink arg) throws JRException {
        JasperReport report = JasperCompileManager.compileReport("jasper/" + arg.getHyperlinkReference() + ".jrxml");
        JasperPrint jasperPrint = JasperFillManager.fillReport(report, new HashMap<String, Object>());
        HyperLinkTest nextReport = new HyperLinkTest(jasperPrint);
        openReport("Navigated to", JFrame.DISPOSE_ON_CLOSE, nextReport);        
    }

    /**
     * static method that creates a frame and adds the JRViewer to it and 
     * open a new frame with the viewer
     */
    public static void openReport(String title, int defaultCloseOperation, JRViewer hyperLinkReport){
      SwingUtilities.invokeLater(new Runnable() {

        @Override
        public void run() {
            JFrame frame = new JFrame(title);
            frame.setDefaultCloseOperation(defaultCloseOperation);
            frame.getContentPane().setLayout(new BorderLayout());
            frame.getContentPane().add(hyperLinkReport,BorderLayout.CENTER);
            frame.pack();
            frame.setLocationRelativeTo(null);
            frame.setVisible(true);
        }
      });
    }

    /**
     *  Main method to test
     */
    public static void main(String[] args) throws JRException {
        JasperReport report = JasperCompileManager.compileReport("jasper/hyperlink1.jrxml");
        JasperPrint jasperPrint = JasperFillManager.fillReport(report, new HashMap<String, Object>());
        HyperLinkTest test = new HyperLinkTest(jasperPrint);
        openReport("Test hyperlink", JFrame.EXIT_ON_CLOSE, test);

    }   

}

Jrxml (reports)

As can be seen in code I'm using hyperlinkType="ReportExecution" and in passing name of next report in hyperlinkReferenceExpression.

Report 1 (hyperlink1.jrxml)

<?xml version="1.0" encoding="UTF-8"?>
<jasperReport xmlns="http://jasperreports.sourceforge.net/jasperreports" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://jasperreports.sourceforge.net/jasperreports http://jasperreports.sourceforge.net/xsd/jasperreport.xsd" name="hyperlink1" pageWidth="595" pageHeight="842" whenNoDataType="AllSectionsNoDetail" columnWidth="555" leftMargin="20" rightMargin="20" topMargin="20" bottomMargin="20" uuid="601103bc-66ab-45a5-8422-ccb6f3e02ec2">
    <queryString>
        <![CDATA[]]>
    </queryString>
    <title>
        <band height="50">
            <textField hyperlinkType="ReportExecution">
                <reportElement x="0" y="0" width="100" height="20" uuid="8dc8f664-60b3-4b10-8a55-23120bea1f85"/>
                <textElement>
                    <font size="14" isBold="true"/>
                </textElement>
                <textFieldExpression><![CDATA["Hello"]]></textFieldExpression>
                <hyperlinkReferenceExpression><![CDATA["hyperlink2"]]></hyperlinkReferenceExpression>
            </textField>
        </band>
    </title>
</jasperReport>

Report 2 (hyperlink2.jrxml)

<?xml version="1.0" encoding="UTF-8"?>
<jasperReport xmlns="http://jasperreports.sourceforge.net/jasperreports" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://jasperreports.sourceforge.net/jasperreports http://jasperreports.sourceforge.net/xsd/jasperreport.xsd" name="hyperlink1" pageWidth="595" pageHeight="842" whenNoDataType="AllSectionsNoDetail" columnWidth="555" leftMargin="20" rightMargin="20" topMargin="20" bottomMargin="20" uuid="601103bc-66ab-45a5-8422-ccb6f3e02ec2">
    <queryString>
        <![CDATA[]]>
    </queryString>
    <title>
        <band height="50">
            <textField hyperlinkType="ReportExecution">
                <reportElement x="113" y="0" width="100" height="20" uuid="8dc8f664-60b3-4b10-8a55-23120bea1f85"/>
                <textElement>
                    <font size="14" isBold="true"/>
                </textElement>
                <textFieldExpression><![CDATA["World"]]></textFieldExpression>
                <anchorNameExpression><![CDATA["World"]]></anchorNameExpression>
                <hyperlinkReferenceExpression><![CDATA["hyperlink1"]]></hyperlinkReferenceExpression>
            </textField>
        </band>
    </title>
</jasperReport>

Result

First window will open with "Hello", if you click "Hello", second window will open with "World"

Output

Notes: If I did this application probably I would pre-compile all .jrxml to .jasper, hence avoid compiling during run-time and probably I would have used multiple classes (1 for frame, 1 for viewer) avoiding static methods, however I have simplified to better fit SO format, concentrating on showing how a JRHyperLinkListener can be implemented in a Swing application.

How to pass report parameters and other data

Can you please tell me how to pass connection Object and other parameters from first report to second from this comment

To pass objects (fields, parameters, variables or any other expression) to the JRHyperlinkListener you should hyperlinkParameter in jrxml.

Example (see the hyperlinkParameter and it's hyperlinkParameterExpression)

<?xml version="1.0" encoding="UTF-8"?>
<jasperReport xmlns="http://jasperreports.sourceforge.net/jasperreports" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://jasperreports.sourceforge.net/jasperreports http://jasperreports.sourceforge.net/xsd/jasperreport.xsd" name="hyperlink1" pageWidth="595" pageHeight="842" whenNoDataType="AllSectionsNoDetail" columnWidth="555" leftMargin="20" rightMargin="20" topMargin="20" bottomMargin="20" uuid="601103bc-66ab-45a5-8422-ccb6f3e02ec2">
    <parameter name="reportDate" class="java.util.Date" isForPrompting="false">
        <defaultValueExpression><![CDATA[new java.util.Date()]]></defaultValueExpression>
    </parameter>
    ....
            <textField hyperlinkType="ReportExecution">
                <reportElement x="0" y="0" width="100" height="20" uuid="8dc8f664-60b3-4b10-8a55-23120bea1f85"/>
                <textElement>
                    <font size="14" isBold="true"/>
                </textElement>
                <textFieldExpression><![CDATA["Hello"]]></textFieldExpression>
                <hyperlinkReferenceExpression><![CDATA["hyperlink2"]]></hyperlinkReferenceExpression>
                <hyperlinkParameter name="reportTime">
                    <hyperlinkParameterExpression><![CDATA[$P{reportDate}]]></hyperlinkParameterExpression>
                </hyperlinkParameter>
            </textField>
        ....
</jasperReport>

This parameter can now be accessed by the JRHyperlinkListener, in example I pass it to parameter map for next report, naturally the jphlp.getValue() will continue to be instanceof java.util.Date

@Override
public void gotoHyperlink(JRPrintHyperlink arg) throws JRException {
    Map<String, Object> nextReportParams = new HashMap<>();
    List<JRPrintHyperlinkParameter> params = arg.getHyperlinkParameters().getParameters();
    for (JRPrintHyperlinkParameter jphlp : params) {
        if ("reportTime".equals(jphlp.getName())){
            nextReportParams.put("previousReportTime",jphlp.getValue());                
        }
    }

    JasperReport report = JasperCompileManager.compileReport("jasper/" + arg.getHyperlinkReference() + ".jrxml");
    JasperPrint jasperPrint = JasperFillManager.fillReport(report, nextReportParams);
    HyperLinkTest nextReport = new HyperLinkTest(jasperPrint);
    openReport("Navigated to", JFrame.DISPOSE_ON_CLOSE, nextReport);        
}

Notes: Watch out passing main report datasource (this will be at the end, you cannot re-use it, if you do not rewind it first) and connection (this may be closed), it's better to pass a new connection to next report.

Upvotes: 3

Related Questions