I am using a Java application that allows you to add extensions written in Java. I wish to run a JasperReports viewer within an extension. As a test I have this code:
package com.moneydance.modules.features.jasperreports;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import javax.swing.JFrame;
import net.sf.jasperreports.engine.JRDataSource;
import net.sf.jasperreports.engine.JREmptyDataSource;
import net.sf.jasperreports.engine.JRException;
import net.sf.jasperreports.engine.JasperFillManager;
import net.sf.jasperreports.engine.JasperPrint;
import net.sf.jasperreports.engine.JasperReport;
import net.sf.jasperreports.engine.util.JRLoader;
import net.sf.jasperreports.swing.JRViewer;
public class MyJasperReport extends JFrame{
JasperReport report;
public MyJasperReport(Main main) throws JRException, IOException{
String sourceFileName = "c://users/miker/workspace/JasperReports-6.7.0/test" +
"/jasper_report_template.jasper";
Map<String,Object> parameters = new HashMap<>();
JasperReport report =(JasperReport)JRLoader.loadObjectFromFile(sourceFileName);
JRDataSource dataSource = new JREmptyDataSource();
JasperPrint jasperPrint = null;
JRViewer viewer = null;
try {
jasperPrint = JasperFillManager.fillReport(report, parameters,dataSource);
}
catch (JRException e) {
e.printStackTrace();
}
if (jasperPrint != null) {
viewer = new JRViewer(jasperPrint);
if (viewer !=null) {
getContentPane().add(viewer);
}
}
}
}
This fails with a null pointer exception on the line:
btnSave.setIcon(new javax.swing.ImageIcon(getClass().getResource("/net/sf/jasperreports/view/images/save.GIF")));
within the class JRViewerToolBar
If I run this in debug through Eclipse it works. If I include the JRViewer and JRViewerToolBar classes in my code and change the code to use the following snippet:
public Image getIcon(String action) {
try {
loader = getClass().getClassLoader();
java.io.InputStream in =
loader.getResourceAsStream(action);
if (in != null) {
ByteArrayOutputStream bout = new ByteArrayOutputStream(1000);
byte buf[] = new byte[256];
int n = 0;
while((n=in.read(buf, 0, buf.length))>=0)
bout.write(buf, 0, n);
return Toolkit.getDefaultToolkit().createImage(bout.toByteArray());
}
} catch (Throwable e) { }
return null;
}
where action is "/net/sf/jasperreports/view/images/save.GIF" it also works.
It is obviously a problem with determining the resource path. I suspect the app I am using uses its own class loader to load my extension.
The question is: Is there a way of loading the JasperReports classes so they behave themselves? Alternatively all I can see is having a modified version of JasperReports in my extension, which is going to introduce bugs and be a maintenance nightmare.
EDIT
This is not a duplicate of the File Resolver question. This is about the class loader used to load the Jasper classes from within an application.