atomatically compile subreports

I have an app that has as input jrxml file names, and outputs the pdf reports. So I am given a "mainReport.jrxml" string, and should output the pdf.

I can easily compile "mainReport" to compiledDirectory, load it into a JasperReport object and then call JasperFillManager.fillReport ()

But in the case of a report having subreports, how do I find that mainReport subreports (and what are their filenames) to compile those also?
there is no JasperReport.getSubeports() or something similar... any ideas?

I hope I was explicit enough
dusca's picture
454
Joined: May 13 2008 - 3:49pm
Last seen: 3 months 1 week ago

18 Answers:

Yeah we had this issue, so we implemented this

Code:
<br />
<subreportExpression  class="net.sf.jasperreports.engine.JasperReport"><![CDATA[JasperCompileManager.compileReport(getClass().getResource("/templates/subreport.jrxml"«»).openStream())]]></subreportExpression><br />
</td></tr></tbody></table><br />
<br />
within the mainReport thereby compiling the subreport jrxml everytime the main report is run.<br />
<br />
We have since changed this to compile and jar up all our jrxml files in a ant script, which then also handles all the fonts and customizer classes we have to go with our reports.
greylimbo's picture
434
Joined: Apr 9 2007 - 7:54pm
Last seen: 16 years 5 months ago
dusca wrote:
But in the case of a report having subreports, how do I find that mainReport subreports (and what are their filenames) to compile those also?
there is no JasperReport.getSubeports() or something similar... any ideas?


If you use JR 2.0.3 or newer, you can iterate on all the subreports in a report via [url=http://jasperreports.sourceforge.net/api/net/sf/jasperreports/engine/uti...
Code:
<br />
JRElementsVisitor.visitReport(jr, new JRVisitorSupport() {<br />
	@Override<br />
	public void visitSubreport(JRSubreport subreport) {<br />
		..do whatever you have to do with the subreport..<br />
	}<br />
});<br />
</td></tr></tbody></table><br />
<br />
Note that if you want to determine the "filename" of the subreport, you'll have to make some assumptions on the subreport expressions, since such expressions can be arbitrarily complex and don't necessarily consists of a static filename.<br />
<br />
HTH,<br />
Lucian
lucianc's picture
87357
Joined: Jul 17 2006 - 1:10am
Last seen: 2 hours 36 min ago
thanks lucian, greylimbo.
tried first the greylimbo approach but didn't quite work as i needed, so i am using lucian's solution

so now I have something along the lines of:

Code:
JasperCompileManager.compileReportToFile(jrxmlPath,jasperPath);<br />
ret = (JasperReport) JRLoader.loadObject(jasperPath);<br />
JRElementsVisitor.visitReport(ret, new SubreportVisitor(sourcePath, destinationPath));</td></tr></tbody></table><br />
<br />
and in my visitor I get the subreport path and also<br />
<br />
JasperCompileManager.compileReportToFile(subReportJrxmlPath, jasperPath);<br />
<br />
<br />
but at runtime I get a <br />
<table align="center" border="0" cellpadding="3" cellspacing="1" width="90%"><tbody><tr><td><b>Code:</b></td></tr><tr><td><pre>net.sf.jasperreports.engine.JRException: Could not load object from location : MySubReport.jasper<br />
	at net.sf.jasperreports.engine.util.JRLoader.loadObjectFromLocation(JRLoader.java:267)<br />
	at net.sf.jasperreports.engine.fill.JRFillSubreport.evaluateSubreport(JRFillSubreport.java:308)</td></tr></tbody></table><br />
<br />
<br />
am I supposed to do a JRLoader.loadObject for the supreport too,or what am I missing?<br />
the jasper files exist and are all in the same dir. <br />
<br />
thanks
dusca's picture
454
Joined: May 13 2008 - 3:49pm
Last seen: 3 months 1 week ago
to answer my own question, loadObject has no effect.

so it's not that

later edit:

this is killing me now!

I have a report that has one subreport. the subreport expression is something like "SubraportulMeu.jasper"

that works perfectly with the code explained above.

then another report, but with two subreports, with the same expression - gives me the "cannot load" exception.

i quadruple checked but just can't figure out what the heck is the difference, why one works but the other doesn't. to the first i only send $P{} params, to the second i send $P{} and $F{}. that is the only thing that is different, but shouldn't be relevant.
Post edited by: dusca, at: 2008/05/14 15:19
dusca's picture
454
Joined: May 13 2008 - 3:49pm
Last seen: 3 months 1 week ago
Subreport locations are interpreted at runtime as a filename, a classloader resource or a URL.

So for "MySubReport.jasper" to be resolved, it should either be a file in the JVM's working directory, or a resource on your application's classpath (so the folder where you have the *.jasper files would have to be part of the classpath).

Regards,
Lucian
lucianc's picture
87357
Joined: Jul 17 2006 - 1:10am
Last seen: 2 hours 36 min ago
lucian, then how is it explained that one of the reports works without a full abstract path? the same directories are used in both cases . all jrxml files are in one directory and all jasper files in another.
dusca's picture
454
Joined: May 13 2008 - 3:49pm
Last seen: 3 months 1 week ago
It's rather difficult to tell why that happens without seeing it happen. Is there a way I could reproduce the behaviour?
Post edited by: lucianc, at: 2008/05/14 17:41
lucianc's picture
87357
Joined: Jul 17 2006 - 1:10am
Last seen: 2 hours 36 min ago
i found out why the particular one was created. eclipse forgot to delete the jasper file from the bin directory, so it was in the run dir.


so ..
in the end i used greylimbo's solution after all.

thank you, it is quite a trick.

i cannot imagine another way, to use a relative path to the subreport
Post edited by: dusca, at: 2008/05/14 20:06
dusca's picture
454
Joined: May 13 2008 - 3:49pm
Last seen: 3 months 1 week ago

Hi

I'm coming back to this with a problem.

So my Subreport is defined using this expression:

                    <connectionExpression><![CDATA[$P{REPORT_CONNECTION}]]></connectionExpression>
                    <subreportExpression  class="net.sf.jasperreports.engine.JasperReport"><![CDATA[net.sf.jasperreports.engine.JasperCompileManager.compileReport(getClass().getResource("Subreport.jrxml").openStream())]]></subreportExpression>
 

If I run and execute the report from Ireport, the subreport is loaded, it all works like a charm

But from my application,  when I generate it using

JasperPrint jPrint = JasperFillManager.fillReport(rep, params, conn);

        JRExporter exporter = getExporter(pdf);
        exporter.setParameter(JRExporterParameter.JASPER_PRINT, jPrint);
        exporter.setParameter(JRExporterParameter.OUTPUT_STREAM, byteArrayOutputStream);
        exporter.exportReport();

    
 

it doesn't work. No exception is thrown, it just doesn't embed the subreport.

So how can this be? Do I need to do something more in my reporting app?

dusca's picture
454
Joined: May 13 2008 - 3:49pm
Last seen: 3 months 1 week ago

You need to have Subreport.jrxml present as a resource on the application classpath, e.g. placed in a folder which is included on the classpath.

Regards,

Lucian

lucianc's picture
87357
Joined: Jul 17 2006 - 1:10am
Last seen: 2 hours 36 min ago

thanks, that worked!

dusca's picture
454
Joined: May 13 2008 - 3:49pm
Last seen: 3 months 1 week ago

Isn't it a bit kind of inperformance to (re)compile the jrxml everytime the SubReport is loaded?

Imagine you have a placed the SubReport-Element in detail of MasterReport and have 1000 records... with your SubReportExpression you will now have 1000 compiles, isn't it????

So I would pass the compiled JasperReport Object as parameter or use a scriptlet does check wheter the jrxml must be (re)compiled or not!??!?! So as the SubReport-design isn't changed normally while fill process it should be compiled just once and not at each call!??!?!?!??

 

just my two cents.

C-Box

C-Box's picture
24125
Joined: Jul 19 2006 - 5:58pm
Last seen: 1 month 2 days ago

you are correct.

 for each subreport in a detail field there is a lot of overhead (the sql query would be more expensive i think - i may be wrong here, so plese correct me) - that is why i embed my subreports in the summary band, or in a new report group's header/foooter

But now that you pointed out the performance issue, I used the SubreportVisitor lucian suggested to compile the sources, and passed the subreport dir parameter to the report.

 

Thanks!

 

 

dusca's picture
454
Joined: May 13 2008 - 3:49pm
Last seen: 3 months 1 week ago

I all

i have tryed the solution using the following line:

<subreportExpression class="net.sf.jasperreports.engine.JasperReport"><![CDATA[net.sf.jasperreports.engine.JasperCompileManager.compileReport(getClass().getResource("/prova/sub_dummy.jrxml").openStream())]]></subreportExpression>

on my main.jrxml report file

works great from my webapp (jsp), but if i open the file with IREPORT (v 3.5.2) and use "preview" button,  that gives me the following error:

Error filling print... Error evaluating expression :      Source text : net.sf.jasperreports.engine.JasperCompileManager.compileReport(getClass().getResource("/prova/sub_dummy.jrxml").openStream())
net.sf.jasperreports.engine.fill.JRExpressionEvalException: Error evaluating expression :      Source text : net.sf.jasperreports.engine.JasperCompileManager.compileReport(getClass().getResource("/prova/sub_dummy.jrxml").openStream())      at net.sf.jasperreports.engine.fill.JREvaluator.evaluate(JREvaluator.java:197)      at net.sf.jasperreports.engine.fill.JRCalculator.evaluate(JRCalculator.java:574)      at net.sf.jasperreports.engine.fill.JRCalculator.evaluate(JRCalculator.java:542)      at net.sf.jasperreports.engine.fill.JRFillElement.evaluateExpression(JRFillElement.java:872)      at net.sf.jasperreports.engine.fill.JRFillSubreport.evaluateSubreport(JRFillSubreport.java:283)      at net.sf.jasperreports.engine.fill.JRFillSubreport.evaluate(JRFillSubreport.java:270)      at net.sf.jasperreports.engine.fill.JRFillElementContainer.evaluate(JRFillElementContainer.java:260)      at net.sf.jasperreports.engine.fill.JRFillBand.evaluate(JRFillBand.java:486)      at net.sf.jasperreports.engine.fill.JRVerticalFiller.fillTitle(JRVerticalFiller.java:312)      at net.sf.jasperreports.engine.fill.JRVerticalFiller.fillReportStart(JRVerticalFiller.java:248)      at net.sf.jasperreports.engine.fill.JRVerticalFiller.fillReport(JRVerticalFiller.java:114)      at net.sf.jasperreports.engine.fill.JRBaseFiller.fill(JRBaseFiller.java:911)      at net.sf.jasperreports.engine.fill.JRBaseFiller.fill(JRBaseFiller.java:814)      at net.sf.jasperreports.engine.fill.JRFiller.fillReport(JRFiller.java:63)      at net.sf.jasperreports.engine.JasperFillManager.fillReport(JasperFillManager.java:421)      at net.sf.jasperreports.engine.JasperFillManager.fillReport(JasperFillManager.java:251)      at com.jaspersoft.ireport.designer.compiler.IReportCompiler.run(IReportCompiler.java:898)      at org.openide.util.RequestProcessor$Task.run(RequestProcessor.java:561)      at org.openide.util.RequestProcessor$Processor.run(RequestProcessor.java:986)  Caused by: net.sf.jasperreports.engine.JRException: Could not instantiate report compiler : it.businesslogic.ireport.compiler.ExtendedJRJdtCompiler      at net.sf.jasperreports.engine.JasperCompileManager.getCompiler(JasperCompileManager.java:520)      at net.sf.jasperreports.engine.JasperCompileManager.compileReport(JasperCompileManager.java:219)      at net.sf.jasperreports.engine.JasperCompileManager.compileReport(JasperCompileManager.java:205)      at main_1245143465937_710977.evaluate(main_1245143465937_710977:183)      at net.sf.jasperreports.engine.fill.JREvaluator.evaluate(JREvaluator.java:186)      ... 18 more  Caused by: java.lang.ClassNotFoundException: it.businesslogic.ireport.compiler.ExtendedJRJdtCompiler      at java.net.URLClassLoader$1.run(URLClassLoader.java:200)      at java.security.AccessController.doPrivileged(Native Method)      at java.net.URLClassLoader.findClass(URLClassLoader.java:188)      at java.lang.ClassLoader.loadClass(ClassLoader.java:307)      at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:301)      at java.lang.ClassLoader.loadClass(ClassLoader.java:252)      at org.netbeans.ProxyClassLoader.loadClass(ProxyClassLoader.java:231)      at java.lang.ClassLoader.loadClass(ClassLoader.java:252)      at java.lang.ClassLoader.loadClassInternal(ClassLoader.java:320)      at java.lang.Class.forName0(Native Method)      at java.lang.Class.forName(Class.java:247)      at net.sf.jasperreports.engine.util.JRClassLoader.loadClassForRealName(JRClassLoader.java:179)      at net.sf.jasperreports.engine.util.JRClassLoader.loadClassForName(JRClassLoader.java:119)      at net.sf.jasperreports.engine.JasperCompileManager.getCompiler(JasperCompileManager.java:515)      ... 22 more 
Print not filled. Try to use an EmptyDataSource...

anyone knows the problem and a solution to it?

maybe i have missing something like a particular jar in the classpath?

thanks,

Mat

matmosis's picture
190
Joined: Jun 16 2009 - 2:06am
Last seen: 14 years 3 months ago
the file ""/prova/sub_dummy.jrxml" is in a jar that i had included in the IREPORT classpath...
matmosis's picture
190
Joined: Jun 16 2009 - 2:06am
Last seen: 14 years 3 months ago

 Hi friend,

I am also try this, but the sub report not displayed.

sundarperiannan's picture
Joined: Jul 25 2009 - 9:36am
Last seen: 9 years 4 months ago

Hi,

 

It is like saying: My friend, I have the same car and it also does not start.

Well, there are 1 million reasons for the car not to start.

So you better open up a new thread and provide as much details as you can, with report templates and PDFs and so on.

 

Thank you,

Teodor

 

teodord's picture
53532
Joined: Jun 30 2006 - 9:00am
Last seen: 12 hours 57 sec ago

general solution/background regarding the path handling and compilation: http://stackoverflow.com/questions/4364205/jasperserver-unable-to-locate...

andreasX's picture
863
Joined: Nov 8 2013 - 2:31am
Last seen: 6 years 6 months ago
Feedback