Jump to content
  • JRPdfExporter may suppresses OutOfMemoryError


    jvaudry
    Assigned User lucianc
    CategoryBug report
    PriorityNormal
    ReproducibilityAlways
    ResolutionFixed
    SeverityMinor
    StatusClosed

    Using Jasper Reports v1.2.3

     

    Steps to Reproduce:

     

    (1) Fill a large jasper report.

    (2) Export the report using the JRPdfExporter.

    (3) Make sure the exportReport() method fails with an OutOfMemoryError.

     

    Expected Results:

    - We expect to see an OutOfMemoryError being thrown.

     

    Actual Results:

    - The PdfWriter object throws a RuntimeException. There is no mention of the OutOfMemoryError in the stack trace.

    - The OutOfMemoryError is completely suppressed and this makes debugging the error difficult.

    - Here is the stack trace:

     

    java.lang.RuntimeException: The name 'MyReference123' has no local destination.

    at com.lowagie.text.pdf.PdfWriter.addLocalDestinations(Unknown Source)

    at com.lowagie.text.pdf.PdfDocument.close(Unknown Source)

    at com.lowagie.text.Document.close(Unknown Source)

    at net.sf.jasperreports.engine.export.JRPdfExporter.exportReportToStream(JRPdfExporter.java:473)

    at net.sf.jasperreports.engine.export.JRPdfExporter.exportReport(JRPdfExporter.java:260)

     

     

    Suggested Solution:

     

    - Refactor the exception handling in the exportReport() method so that if the finally block throws an exception, the method will still propagate the first/original exception instead of the exception from the finally block.

     

    Here is some psuedo-code:

     

    Throwable first = null;

    try {

     

    // do the export here.

     

    } catch (Throwable newValue) {

    // this is the last of all the catch blocks.

    first = newValue;

     

    } finally {

     

    try {

     

    // perform the close() resources here.

     

    } catch (Throwable finallyException) {

    if (first != null) {

    // propagate the first/original exception

    } else {

    // propagate the exception from the close() method

    }

    }

    }

     

     

     



    User Feedback

    Recommended Comments

     

    Hi,

     

    How did you find out it was about an OutOfMemoryError if there was no trace of it?

    Did you see the iText library making a catch on an OutOfMemoryError and eating it up or wrapping it into a RuntimeException?

     

    We need stronger evindence about such behavior before doing anything about it.

     

    Thank you,

    Teodor

     

    Link to comment
    Share on other sites

     

    I have just re-run the test case with a debugger and confirmed the OutOfMemoryError is being thrown. Here is listing of the events:

     

    (1) Here is the stack trace of the original OutOfMemoryError that occurs during the export phase:

     

    java.lang.OutOfMemoryError: Java heap space

    ByteDataDto$ByteStreamCopier.write(byte[], int, int) line: 248

    BufferedOutputStream.write(byte[], int, int) line: 105

    OutputStreamCounter.write(byte[], int, int) line: not available

    ByteArrayOutputStream.writeTo(OutputStream) line: 112

    PdfImage(PdfStream).toPdf(PdfWriter, OutputStream) line: not available

    PdfIndirectObject.writeTo(OutputStream) line: not available

    PdfWriter$PdfBody.add(PdfObject, int, boolean) line: not available

    PdfWriter$PdfBody.add(PdfObject, int) line: not available

    PdfWriter$PdfBody.add(PdfObject) line: not available

    PdfWriter.addToBody(PdfObject) line: not available

    PdfWriter.add(PdfImage) line: not available

    PdfWriter.addDirectImageSimple(Image) line: not available

    PdfContentByte.addImage(Image, float, float, float, float, float, float, boolean) line: not available

    PdfContentByte.addImage(Image, float, float, float, float, float, float) line: not available

    PdfDocument.writeLineToContent(PdfLine, PdfContentByte, PdfContentByte, Object[], float) line: not available

    ColumnText.go(boolean) line: not available

    ColumnText.go() line: not available

    JRPdfExporter.exportImage(JRPrintImage) line: 1162

    JRPdfExporter.exportElements(Collection) line: 519

    JRPdfExporter.exportPage(JRPrintPage) line: 487

    JRPdfExporter.exportReportToStream(OutputStream) line: 452

    JRPdfExporter.exportReport() line: 260

     

    (2) The OutOfMemoryError is not caught by iText. However, there is a finally clause which is executed in the JRPdfExporter. In the finally clause it calls Document.close(). The close() method throws a RuntimeException and it is the runtime exception that propagates. The OutOfMemoryError is discarded because of it. Here is the final stack trace we receive:

     

    java.lang.RuntimeException: The name \'MyReference123\' has no local destination.

    at com.lowagie.text.pdf.PdfWriter.addLocalDestinations(Unknown Source)

    at com.lowagie.text.pdf.PdfDocument.close(Unknown Source)

    at com.lowagie.text.Document.close(Unknown Source)

    at net.sf.jasperreports.engine.export.JRPdfExporter.exportReportToStream(JRPdfExporter.java:473)

    at net.sf.jasperreports.engine.export.JRPdfExporter.exportReport(JRPdfExporter.java:260)

     

    I believe the problem is that since there is an OutOfMemoryError, the whole report cannot be exported. So we end up with only half a report. During the Document.close() method it tries to create the links in the table of contents. There are local references that do not have destinations since the destination part of the report was not exported.

    Link to comment
    Share on other sites


×
×
  • Create New...