0
com.hughes.exception.HughesException
    at com.hughes.service.serviceImpl.HomeServiceImpl.sendTicketEmail(HomeServiceImpl.java:1094)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)

.......................................................
..........................................

Caused by: net.sf.jasperreports.engine.JRException: Resource not found at : nullinvoiceDetail.jasper
    at net.sf.jasperreports.repo.RepositoryUtil.getResource(RepositoryUtil.java:155)
    at net.sf.jasperreports.repo.RepositoryUtil.getReport(RepositoryUtil.java:126)
    at net.sf.jasperreports.engine.fill.JRFillSubreport.evaluateReport(JRFillSubreport.java:317)
    at net.sf.jasperreports.engine.fill.JRFillSubreport.evaluateSubreport(JRFillSubreport.java:347)
    at net.sf.jasperreports.engine.fill.JRFillSubreport.evaluate(JRFillSubreport.java:275)
    at net.sf.jasperreports.engine.fill.JRFillElementContainer.evaluate(JRFillElementContainer.java:257)
    at net.sf.jasperreports.engine.fill.JRFillBand.evaluate(JRFillBand.java:473)
    at net.sf.jasperreports.engine.fill.JRVerticalFiller.fillColumnBand(JRVerticalFiller.java:2021)
    at net.sf.jasperreports.engine.fill.JRVerticalFiller.fillDetail(JRVerticalFiller.java:755)
    at net.sf.jasperreports.engine.fill.JRVerticalFiller.fillReportStart(JRVerticalFiller.java:265)
    at net.sf.jasperreports.engine.fill.JRVerticalFiller.fillReport(JRVerticalFiller.java:128)
    at net.sf.jasperreports.engine.fill.JRBaseFiller.fill(JRBaseFiller.java:836)
    at net.sf.jasperreports.engine.fill.JRBaseFiller.fill(JRBaseFiller.java:765)
    at net.sf.jasperreports.engine.fill.JRFiller.fillReport(JRFiller.java:84)
    at net.sf.jasperreports.engine.JasperFillManager.fillReport(JasperFillManager.java:624)
    at com.hughes.service.serviceImpl.HomeServiceImpl.sendTicketEmail(HomeServiceImpl.java:1046)
    ... 81 more
JasperReport jasperReport = JasperCompileManager.compileReport(hdnWebInfPath+seperator+"reports"+seperator+"invoice.jrxml");
                        JasperPrint jasperPrint = JasperFillManager.fillReport(jasperReport, model, new JREmptyDataSource());
                        JasperExportManager.exportReportToPdfFile(jasperPrint, fPath+seperator+fileName);

this works when simple report not working for sub reports...

Alex K
  • 22,315
  • 19
  • 108
  • 236
Ankit Mekwan
  • 1
  • 1
  • 1
  • You can view [this post](http://stackoverflow.com/questions/4825726/how-to-load-subreport-resources-with-jasper), [this one](http://stackoverflow.com/questions/9785451/generate-jasper-report-with-subreport-from-java) and [this one](http://stackoverflow.com/questions/3702565/how-to-pass-jasper-file-path-to-subreport-of-subreport) – Alex K May 15 '12 at 11:42

1 Answers1

1

My Jarper knowledge is couple versions old, but lets hope this is helpful.

This is because jasper does not find your subreport. Jasper can compile your report, but it does not compile referenced subreports when you call compileReport. When filling the report referenced subreports are not found because they are not available in working directory.

(Compiling report every time it is requested is kind a bad idea (unless you have some really heavy reasons to do so).)

There are couple of ways solving this. One would be making sure the the paths are correct and precompiling the reports before application deployment. Links Alex K provided are an excellent source for this. If in application compilation is required then using solution below is possible:

In web application I've found that a working practice is to handle compilation and filling your reports is to manage it manually. Here is helper class I wrote. Hope that it is useful (it uses spring, but those parts are easily replaceable).

public class ReportSource {

    // Key = document name, Value = path to .jrxml
    private Map<String, String> reports;
    private final Map<String, JasperReport> compiled;

    private final boolean lazy;

    private final Logger log = Logger.getLogger(ReportSource.class);

    public ReportSource(final boolean lazyBuild) {
        super();
        lazy = lazyBuild;
        compiled = new HashMap<String, JasperReport>();
    }

    public void setCompileTargets(final Map<String, String> targets) {
        reports = new HashMap<String, String>(targets);
        if (!lazy) {
            for (final String key : targets.keySet()) {
                compile(key);
            }
        }
    }

    public JasperReport getReport(final String reportName) {
        if (compiled.get(reportName) == null) { // not found or not compiled
            log.info("Lazily compiling: " + reportName);
            return compile(reportName);
        }
        return compiled.get(reportName);
    }

    private JasperReport compile(final String reportName) {
        final String path = reports.get(reportName);

        InputStream fis = null;
        JasperReport report = null;
        try {
            final FileSystemResourceLoader resourceLoader = new FileSystemResourceLoader();
            fis = resourceLoader.getResource(path).getInputStream();
            log.info("Compiling report: " + reportName + " (" + path + ")");
            report = JasperCompileManager.compileReport(fis);
        } catch (final IOException ioe) {
            throw new IllegalStateException("Configuration error file: " + path + " (for key: " + reportName +") not found.", ioe);
        } catch (final JRException jre) {
            throw new IllegalStateException("Configuration error file: " + path + " (for key: " + reportName +") not found.", jre);
        }

        compiled.put(reportName, report);
        return report;
    }
}

With the help of this class you can refer subreports in documents like this:

<subreport>
    <reportElement x="0" y="0" width="200" height="30"/>
    <subreportParameter name="data">
        <subreportParameterExpression><![CDATA[$P{data}]]></subreportParameterExpression>
    </subreportParameter>
    <subreportParameter name="REPORT_RESOURCE_BUNDLE">
        <subreportParameterExpression><![CDATA[$P{REPORT_RESOURCE_BUNDLE}]]></subreportParameterExpression>
    </subreportParameter>
    <dataSourceExpression><![CDATA[new net.sf.jasperreports.engine.JREmptyDataSource()]]></dataSourceExpression>
    <subreportExpression class="net.sf.jasperreports.engine.JasperReport"><![CDATA[$P{data}.getSubreport("name_of_your_subreport")]]></subreportExpression>
</subreport>

Here $P{data} is suitable object provided as document parameter, where getSubreport() ends up calling ReportSource.getReport(). It could of course be $P{reportSource}.getReport("....") if ReportSource is provided as parameter directly. (We use ReportModel-approach; in short it is presentation model fitted to the context of reports).

Ahe
  • 2,124
  • 3
  • 19
  • 29
  • When you say, "Here $P{data} is suitable object provided as document parameter" and "It could of course be $P{reportSource}.getReport("....") if ReportSource is provided as parameter directly", I'm not sure what you mean. Can you explain more about this `data` or `reportSource` parameter? I get that it's an object that you can call .getReport() on, but how do I set that up? Right now I have a ReportGenerator object that has a compileReport() method. But if I use `reportGenerator` it says: `JRValidationException: Report design not valid Parameter not found : reportGenerator` – Tyler Cheek Dec 05 '19 at 17:33
  • Its been years since I last used jasperReports. You can give paremetrers / arguments to a report much like you could give parameters to a function (common idiom was Map). I however used custom class to catch errors early on and its parameter name was data (${data}). I called this pattern reportModel (much like viewModel in MVVM). ReportModel contained reportGenerator instance (source above). When report renderiging calls getSubreport("...") reportModel forwards that call to reportSource. You can of course give reportSource directly as parameter do document (${reportSource}) – Ahe Dec 17 '19 at 12:48