Battling with java.lang.IllegalStateException: getWriter() has already been called for this response


I had a requirement to generate reports as PDF file which will also includes the charts and download them at client’s system. For creating charts, I was using Chart FX 6.5 (Product of Software FX).

And as a part of framework I created a JAVA class which will create the Charts images and return path of the Chart images.(This JAVA class was called by controller, a SERVLET).

There are two constructors for creating ChartServer object. This object is used to design the Chart and assign the values of charts. Lately Chart can be generated by this object.

1) ChartServer chart = new ChartServer();

2) ChartServer chart = new ChartServer(servletContext, request, response);

Initially I used the first option to create Charts.

I saved a path of a creating image in a String variable.

path = chart.getHtmlTag(“1070″, “500″, “PNG”);

and returned this path back to Controller. After all these CONTROLLER will call a method which will create the report with charts in PDF and send the PDF file to the client.

When application is running and I try to download a PDF file, sometimes it was downloading PDF and sometimes it was giving following error.

NullPointerException

chart.getHtmlTag(Unknown source)

I had a feeling that ChartFX was not finding the context path to generate the Charts. Finally came out know that at many places ChartServer internally uses Application context.

So I decided to go to second constructor of ChartServer.

ChartServer chart = new ChartServer(servletContext, request, response);

For sending PDF to client browser I created a method in controller which is the end point of the request.

private void doDownload(final HttpServletResponse resp,

final String filename, final String originalFilename, final String reportType)

throws IOException {

File f = new File(filename);

int length = Constants.ZER0;

ServletOutputStream op = resp.getOutputStream();

resp.setContentType(“application/PDF;charset=UTF-8″);

resp.setContentLength((int) f.length());

resp.setHeader(“Content-Disposition”, “attachment; filename=”" + originalFilename + “”");

byte[] bbuf = new byte[Constants.FIVE_HUNDRED];

DataInputStream in = new DataInputStream(new FileInputStream(f));

while ((in != null) && ((length = in.read(bbuf)) != -1)) {

op.write(bbuf, Constants.ZER0, length);

}

in.close();

op.flush();

op.close();

if (f.exists()) {

f.delete();

}

}

By doing this, I faced another awesome problem.

java.lang.IllegalStateException: getWriter() has already been called for this response

org.apache.catalina.connector.Response.getOutputStream(Response.java:576)

org.apache.catalina.connector.ResponseFacade.getOutputStream(ResponseFacade.java:181)

javax.servlet.http.HttpServlet.service(HttpServlet.java:627)

javax.servlet.http.HttpServlet.service(HttpServlet.java:729)

Oops !! Another exception in developer’s life.

I debugged it and found that everything is going fine before the following line which responsible for generating the Chart image.

path = chart.getHtmlTag(“1070″, “500″, “PNG”);

Exception is coming on this line. So, I believed that ChartServer internally calls getWriter() of ServletResponse.

Now I wanted to know whether Response has been committed or not. I used isCommitted method of Servlet Response (Used it in Controller, separate java class and in doDownload method before ServletOutputStream was being opened) to find it out whether response has been committed or not. But no luck every where I got it as false.

I tried something different this time, I used JSP instead of java class, because in JSP no need to pass context as a parameter. So, I wrote chart code in JSP to create Charts and forwarded the request to another controller which will create the PDF file.

My flow was

Controller ——> JSP ——–> Controller

But these time also no luck. Same old exception.

java.lang.IllegalStateException: getWriter() has already been called for this response

After a lots of trial and error, I decided to reset buffer of the Servlet Response, Following method I used response.resetBuffer() from Servlet Response before I generate the PDF file.

But exception was luckier then me and came all over again.

Then I tried to reset the Servlet Response too using reset() method of Servlet Response.

This time I didn’t get any error/exception and my PDF was generating with appropriate charts and I was able to download it from my Browser too.

So my final PDF creation and downloading method is

public void doDownloadPDF(HttpServletResponse response,

String jasperFilename, String PDFFilename,

Map reportParams, JRDataSource dataSource) throws IOException {

InputStream jasperStream = this.getClass().getClassLoader().getResourceAsStream(

jasperFilename + “.jasper”);

response.reset();

response.resetBuffer(); //This may not required but I feel good to have this.

response.setContentType(“application/PDF;charset=UTF-8″); response.setHeader(“Content-Disposition”, “attachment; filename=”" + PDFFilename + “.PDF” + “”");

//getting jasperReport by loading jasper file

JasperReport jasperReport;

try {

jasperReport = (JasperReport) JRLoader.loadObject(jasperStream);

//getting jasper Print by filling the report

JasperPrint jasperPrint = JasperFillManager.fillReport(jasperReport, reportParams, dataSource);

JasperExportManager.exportReportToPDFStream(jasperPrint, response.getOutputStream());

response.getOutputStream().flush();

response.getOutputStream().close();

} catch (JRException ex) {

Logger.getLogger(JasperReportController.class.getName()).log(Level.SEVERE, null, ex);

}

}

Now my PDFs are generating without any problem. I am using JRE 1.5 and Tomcat 5.5.27.

A battle of a Developer has been appreciated by the Exception and Exception is now demolished!! :-)

Did you enjoy this post? Why not leave a comment below and continue the conversation, or subscribe to my feed and get articles like this delivered automatically to your feed reader.

Comments

You are the best!!!

Thanks for the solution.

I ´ve just added you in my favorites

Regards from Spain

Luis

Leave a comment

(required)

(required)