Hot questions for Using JasperReports in swing

Question:


Answer:

You can use JRTableModelDataSource implementation of JRDataSource interface, which is designed to be used along with Swing TableModel interface. Consider the following snippet:

TableModel model = new TableModelImp(); // TableModel implementation here
JTable table = new JTable(model);    
...
Map params = new HashMap();
...
JRDataSource dataSource = new JRTableModelDataSource(table.getModel());
JasperPrint print = JasperFillManager.fillReport("pathToYourReport.jasper", params, dataSource);
JasperViewer.viewReport(print, true); // true == Exit on Close

See more in this TableModel Data Source example.

See also:

Question:

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?


Answer:

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"

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.

Question:

Recently I updated my project with the newest jasper-reports lib. There is a new JRViewer class (net.sf.jasperreports.swing) which replaced the old one (net.sf.jasperreports.view). Now I can't figure out how to set the export options. The old code was like:

JRPdfSaveContributor pdf = new JRPdfSaveContributor(locale, resBundle);
JRRtfSaveContributor rtf = new JRRtfSaveContributor(locale, resBundle);
JRSingleSheetXlsSaveContributor xls = new JRSingleSheetXlsSaveContributor(locale, resBundle);
JRDocxSaveContributor docx = new JRDocxSaveContributor(locale, resBundle);
viewer.setSaveContributors(new JRSaveContributor[] { pdf, rtf, xls, docx });

Answer:

You'll have to extend net.sf.jasperreports.swing.JRViewer and set the export contributors to JRViewerToolbar. Something like this:

public class MyJRViewer extends JRViewer {
    //define the constructor that you use
    public MyJRViewer(JasperPrint jasperPrint) {
        super(jasperPrint);
    }

    @Override
    protected JRViewerToolbar createToolbar() {
        JRViewerToolbar toolbar = super.createToolbar();

        Locale locale = viewerContext.getLocale();
        ResourceBundle resBundle = viewerContext.getResourceBundle();
        JRPdfSaveContributor pdf = new JRPdfSaveContributor(locale, resBundle);
        JRRtfSaveContributor rtf = new JRRtfSaveContributor(locale, resBundle);
        JRSingleSheetXlsSaveContributor xls = new JRSingleSheetXlsSaveContributor(locale, resBundle);
        JRDocxSaveContributor docx = new JRDocxSaveContributor(locale, resBundle);
        toolbar.setSaveContributors(new JRSaveContributor[] {pdf, rtf, xls, docx});

        return toolbar;
    }   
}

Question:

This is my code

static Connection connHealthInfoSystem = DBConnection.conn("health_info_system");
public static void printDisplayable(String reportPath, Map parameter) {
    JasperDesign jd;
    try {
        jd = JRXmlLoader.load(reportPath);
        JasperReport jr = JasperCompileManager.compileReport(jd);
        JasperPrint jp = JasperFillManager.fillReport(jr, parameter, connHealthInfoSystem);
        JasperViewer.viewReport(jp, false);
    } catch (JRException ex) {
        Logger.getLogger(JasperPrinting.class.getName()).log(Level.SEVERE, null, ex);
    }
}

Based on the current code that I have, how can I increase the size of the width of my report when it pops up?


Answer:

try jd.setPageWidth(999); before JasperCompileManager.compileReport(jd);

Question:

I have created a swing application. I have created a report with iReport 5.6.0. Now whenever I call the report and tried to add the report in JInternalFrame it throws exception. I am sharing my code bellow.

Report Viewer

public class MyReportViewer extends JInternalFrame {
    public MyReportViewer(String fileName){
        this(fileName, null);
    }

    public MyReportViewer(String fileName, HashMap parameter) {
        super("View Report",true,true,true,true);
        try {
            DB_Con db = new DB_Con();

            JasperPrint  print = JasperFillManager.fillReport(fileName,parameter,db.con);
            java.util.List list = print.getPages();

            if(!(list.isEmpty())) {
                JRViewer viewer = new JRViewer(print);

                Container contentPane = super.getContentPane();
                contentPane.removeAll();
                contentPane.add(viewer);

                int sW =(int)Toolkit.getDefaultToolkit().getScreenSize().getWidth();
                int sH = (int)Toolkit.getDefaultToolkit().getScreenSize().getHeight()-50;

                setBounds(0,0,sW,sH);
                setDefaultCloseOperation(DISPOSE_ON_CLOSE);
            } else {
                BOptionPane.showMessageDialog(null,
                        BOptionPane.REPORT_MESSAGE,
                        BOptionPane.ERROR_TITLE,
                        BOptionPane.ERROR_ICON);
            }
        }catch(JRException jre){
            jre.printStackTrace();
        }
    }
}

Main Frame

public class frmMenu extends JFrame {
    public frmMenu(){
        initComponents();
    }

JDesktopPane dPane = new JDesktopPane();

//---- itemAllSizeInfo ----
                    itemAllSizeInfo.setText("All Size List");
                    itemAllSizeInfo.setFont(new Font("Rupali", Font.BOLD, 14));
                    itemAllSizeInfo.addActionListener(new ActionListener(){
                        public void actionPerformed(ActionEvent e) {
                            MyReportViewer sizeInfo = new MyReportViewer(".\\Report\\All_Size_List.jasper");
                            dPane.add(sizeInfo);
                            sizeInfo.setVisible(true);
                        }
                    });

The Exception:

Exception in thread "AWT-EventQueue-0" java.lang.StackOverflowError at net.sf.jasperreports.view.JRViewer$23.getRenderersCache(JRViewer.java:2256) at net.sf.jasperreports.view.JRViewer$23.getRenderersCache(JRViewer.java:2256) at net.sf.jasperreports.view.JRViewer$23.getRenderersCache(JRViewer.java:2256) at net.sf.jasperreports.view.JRViewer$23.getRenderersCache(JRViewer.java:2256) at net.sf.jasperreports.view.JRViewer$23.getRenderersCache(JRViewer.java:2256) at net.sf.jasperreports.view.JRViewer$23.getRenderersCache(JRViewer.java:2256) at net.sf.jasperreports.view.JRViewer$23.getRenderersCache(JRViewer.java:2256) at net.sf.jasperreports.view.JRViewer$23.getRenderersCache(JRViewer.java:2256) at net.sf.jasperreports.view.JRViewer$23.getRenderersCache(JRViewer.java:2256)

Can anyone help to find out to overcome the problem. I am using iReport 5.6.0 and JDK 1.7.0 version


Answer:

This was a bug on the Jasper. Just use the last version.

Question:

This thread is about an oldest bug from jasperreports containing barcode. All Java Swing clients get an exception about serialVersionUID when they are trying to print a remote compiled report, this one downloaded through RMI, HTTP request, etc.


Answer:

Java Swing clients only can see those reports who were rendered by the same JVM version (server), this one for instance:

  1. JVM Server: 1.7.0.71
  2. JVM Client: 17.0.71
But, how we can fix it ?

The first option we have is render those reports as PDF format. For instance:

print = JasperFillManager.fillReport(jasperFile, parameters, connection);
byte[] bi= JasperExportManager.exportReportToPdf(print);

Then return this byte array for clients, so read/write it as PDF stream to local temp file on client side. This one can by mobile, desktop, web, etc.

FileOutputStream fos = new FileOutputStream("/some/file.pdf");
fos.write(bytes);
fos.flush();
fos.close();

The second one, but I think more simple and transparent, is replace the barcode lib that you're using on your reports, from Barbecue to Barcode4J. The image bellow shows what lib you must choose:

And, to keep the same proportion of Barbecue lib of Code 128, you should sets 'Module width' option with value '1.0'.

Other tips

In general, always render reports in PDF there aren't no problems, it's more responsive through clients (web, desktop, mobile, etc.), except when you're working if labels (or stickers), PIMACO 6082 for instance. When you convert jasper to PDF, RTF, or any other format, sometimes their margins are modified in this process.

Question:

I am working on a Java swing based stand alone application, where I have to package my Jasper reports in the jar file. The reports uses sub-reports also.

When I run the reports in eclipse IDE, it works fine, means all report with or without sub-reports are running properly; but when I package them in the jar file, only the reports without sub-reports are working properly and the reports using the subreports are throwing below exception-

Exception in thread "Thread-7" java.util.ConcurrentModificationException
    at java.util.ArrayList$Itr.checkForComodification(Unknown Source)
    at java.util.ArrayList$Itr.next(Unknown Source)
    at net.sf.jasperreports.engine.fill.BaseFillHandle.notifyError(BaseFillHandle.java:210)
    at net.sf.jasperreports.engine.fill.BaseFillHandle$ReportFiller.run(BaseFillHandle.java:135)
    at java.lang.Thread.run(Unknown Source)

The reports are structured in following directory hierarchy-

+ main
|------+ reports
       |--------+ invoice
       |        |--------> invoice_master.jasper
       |        |--------> invoice_sub_report.jasper  
       |---------> end_of_the_day_report.jasper

What I mean is 'end_of_the_day_report.jasper' works fine in the jar package, but '/reports/invoice/invoice_master.jasper' do not, throwing above exception.

I have passed the 'SUBREPORT_DIR' parameter as '/reports/invoice/' for the 'invoice_master.jasper' report.

I am using 'jasperreports 5.6.0' library in my project.


Answer:

Well I found reason for above problem after a lot of test cases and references.

At first site the concurrent modification seems to be strange and seems to be due to concurrent modification of some collection. But in my case below strategy worked for me-

  1. When the report is of single page it is fine to read it even inside the jar package. But for reports having multiple sub-reports will not work inside the jar package, because it is zipped. You have two solutions

    a) You are firm to put the jasper files inside the jar package, than read the post here -

Load all sub-reports using Input Stream in your Java Code, and pass them into the parameters map

In the iReport designer map those parameters with the sub-reports

JasperReport jasperReport = null;
JasperReport subReport = null;
String reportPath = "/reports/invoice/invoice_master.jasper";
String subReportPath = "/reports/invoice/invoice_sub_report.jasper";
try {
//load the the reports
jasperReport = (JasperReport)JRLoader.loadObject(getClass().getResource(reportPath));

subReport = (JasperReport)JRLoader.loadObject(getClass().getResource(subReportPath));

//pass the subReport object as a parameter to the jasperReport
Map<String, Object> reportParams = new HashMap<String, Object>();
params.put("SUB_JASPER", subReport);

//finally pass the parameter map to the report.
JasperPrint jasperPrint = JasperFillManager.fillReport(jasperReport, params, connectionOrOtherDataSource);
//... do something with jasperPrint
} catch (JRException e) {
    e.printStackTrace();
}

In your Jasper file you should have -

i) Create a report parameter "SUB_JASPER" with Parameter Class set to net.sf.jasperreports.engine.JasperReport

ii) Click on the subreport, set the Expression Class property to net.sf.jasperreports.engine.JasperReport and Subreport Expression to the parameter "$P{SUB_JASPER}".

      b) You are flexible to put the jasper reports outside of the jar package, then read below- Put your all reports in reports directory or its sub-directory, where the jar file and reports directory are in same level. If your reports uses images than put them also at the reports directory level under images directory. So your directory structure will becomes now as-

    + myapp.jar
    + images
    |--------->image1.png
    + reports
    |--------+ invoice
    |        |--------> invoice_master.jasper
    |        |--------> invoice_sub_report.jasper  
    |--------> end_of_the_day_report.jasper

Note:- "image1.png" is the image used in jasper reports. When you run the jar file the directory that contains the jar file is automatically in the class-path, so the reports and images are also in search path list. Hope this works for you too!!

Question:

I wrote an app that gathers details about clients and generates a monthly report with Jasper Dynamic Report. until now , my report shows all fields, and some might be blank with some clients, and full in others.

I want to make a dynamic report that chooses only the non empty columns for each client. to accomplish that I have created arrays for :

aggregationSubtotalBuilder, TextColumnBuilder, ConditionalStyleBuilder, StyleBuilder,

so instead of doing this

TextColumnBuilder<Double> offLine  = col.column "OffLine","offline",type.doubleType());
TextColumnBuilder<Double> onLine   = col.column("OnLine","online",type.doubleType());

. . .

im doing this:

for (int i = 0; i < activeColumns.length; i++) 
  {
     activeColumnsForDataSource[i] = activeColumns[i];
     textColumnBuilder[i] = col.column("\"" + activeColumnsForDataSource[i] + "\"","\"" + activeColumns[i] + "\"",type.doubleType()).setTitleFixedHeight(30);
     conditionStyleBuilder[i] = stl.conditionalStyle(cnd.unEqual(textColumnBuilder[i], 0)).setFontSize(12).bold();
     styleBuilder[i] = stl.style().conditionalStyles(conditionStyleBuilder[i]).setBorder(stl.pen1Point());

     textColumnBuilder[i].setStyle(styleBuilder[i]).setHorizontalAlignment(HorizontalAlignment.CENTER);
     aggregationSubtotalBuilder[i] = sbt.sum(textColumnBuilder[i]).setLabel("סהכ" + activeColumns[i]).setLabelStyle(sumLabelStyle).setStyle(dataNameStyle);

where "activeColumns" is an array with the names of all active columns I want to add.

one of the issues I have trouble with is that I have a Date column, that should always be displayed, and it is of a string type:

TextColumnBuilder<String> dayDate  = col.column("תאריך","date",type.stringType()).setStyle(rowNamesStyle);

so I cannot add it to the TextColumnBuilder Array . how can I add it to the report?

in the build() if I do something like this

.columns(//add columns
             textColumnBuilder,dayDate)
       .columnGrid(
             textColumnBuilder,dayDate)

it will only show the last item I added , which is DayDate.

what can I do ?

Please help !

thank you.

dave.


Answer:

columns(textColumnBuilder).addColumn(dayDate)

and remove the ColumnGrid.

now its working :)