0

Currently I am using jasper v 3.7.4

While exporting to any other format (csv,xls,pdf) from the same dataset - I have has no issues.

Exporting to text throws:

java.lang.OutOfMemoryError: Java heap space at java.util.Arrays.copyOf(Arrays.java:3236) at java.io.ByteArrayOutputStream.grow(ByteArrayOutputStream.java:118)

Here is my code:

    byte[] bytes = null;
    JRTextExporter  exporter = new JRTextExporter();
    ByteArrayOutputStream txtReport = new ByteArrayOutputStream();
    exporter.setParameter(JRExporterParameter.JASPER_PRINT, jasperPrint);
    exporter.setParameter(JRExporterParameter.OUTPUT_STREAM, txtReport);
    exporter.setParameter(JRExporterParameter.OUTPUT_FILE_NAME, "mytxt.txt");
    exporter.setParameter(JRExporterParameter.CHARACTER_ENCODING, "UTF-8");
    exporter.setParameter(JRTextExporterParameter.CHARACTER_WIDTH, 2.0F);
    exporter.setParameter(JRTextExporterParameter.PAGE_WIDTH, 100.0F);
    exporter.setParameter(JRTextExporterParameter.CHARACTER_HEIGHT, 4.0F);
    exporter.setParameter(JRTextExporterParameter.PAGE_HEIGHT, 50.0F);
    
    exporter.exportReport();
    bytes = txtReport.toByteArray();

    FileOutputStream fos = new FileOutputStream("c:\\myfile.txt")
    System.out.println(bytes.length/1024+" Kbytes");
    fos.write(bytes, 0, bytes.length);
    fos.flush();
    fos.close();

I am also using a virtualizer as jasperPrint parameter

 JRFileVirtualizer virtualizer = new JRFileVirtualizer(150);
 virtualizer.setReadOnly(false);
 params.put(JRParameter.REPORT_VIRTUALIZER, virtualizer);

But it does not help, and also the following warning is shown:

WARNING: Parameter "REPORT_VIRTUALIZER" already registered, skipping this one.

Given that csv is also a "text" file and is generated without any problem, it is kind of strange that exporting to text fails.

May be something is wrong with the parameters I provide for the exporter?

Thanks.

8
  • @Kayaman You are partially right (regarding the given code) - however the code above was created to replicate the issue - in the real code (which is inside servlet) - there is no FileOutput - everything is done in memory - and as I said earlier cvs is generated perfectly - but text fails. Commented Sep 15, 2020 at 6:30
  • If in the actual code the report is written to any stream (network) etc. it's still the same case. Besides it doesn't matter if the csv is generated perfectly, you're running out of memory. I don't know why you would assume that a successful csv export would mean a successful text export. Text is not the same format as csv, all files are binary, and "text file" is just a distinction made for humans. Commented Sep 15, 2020 at 6:37
  • Thanks for your comments - there were very helpful - of course you are right - I should write directly to stream. Also, I wasn't expecting the text report being filled with so many space characters - that's the reason why the result is huge and gives OOME. Commented Sep 15, 2020 at 6:59
  • One question - the only reason to be writing to temporary ByteArrayOutputStream is to be able to set response.setContentLength(bytes.length); on servlet's response but if I write directly to the stream I have no knowledge of content length ... is there a way to obtain that information ? Commented Sep 15, 2020 at 7:14
  • 1
    Well, then you've got a choice to make. I'd go for the low-memory option, since it's 2020 and I did enough time estimating in the 90's. But if you want to provide your users with that option, then you can increase memory. Commented Sep 15, 2020 at 7:26

2 Answers 2

2

While text and csv may both be text based formats, they're not the same format and therefore do not take the same amount of space.

Generating anything (usually reports) to memory is hazardous since while it may work in testing, a large report in production causing an OOME will wreak havoc.

Use a real stream when generating things. A FileOutputStream, network stream, any proper stream that doesn't store things in memory. If you're using a ByteArrayOutputStream for "real work", you're most likely doing something wrong.

Sign up to request clarification or add additional context in comments.

Comments

0

Immediately output the report to the file, instead of first collecting it.

try (FileOutputStream fos = new FileOutputStream("c:\\myfile.txt");
        BufferedOutputStream bos = new BufferedOutputStream(fos)) {
    JRTextExporter  exporter = new JRTextExporter();
    exporter.setParameter(JRExporterParameter.JASPER_PRINT, jasperPrint);
    exporter.setParameter(JRExporterParameter.OUTPUT_STREAM, bos);
    exporter.setParameter(JRExporterParameter.OUTPUT_FILE_NAME, "mytxt.txt");
    exporter.setParameter(JRExporterParameter.CHARACTER_ENCODING, "UTF-8");
    exporter.setParameter(JRTextExporterParameter.CHARACTER_WIDTH, 2.0F);
    exporter.setParameter(JRTextExporterParameter.PAGE_WIDTH, 100.0F);
    exporter.setParameter(JRTextExporterParameter.CHARACTER_HEIGHT, 4.0F);
    exporter.setParameter(JRTextExporterParameter.PAGE_HEIGHT, 50.0F);

    exporter.exportReport();
}

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.