1

I've recently encountered the following exception...

java.lang.IllegalStateException: Cannot obtain Writer because OutputStream is already in use

I understand the nature of the exception; namely the code can use a Writer or OutputStream but never both in the same request. How is code further down the stack supposed to handle the case where one already exists? OR is there a design/arch pattern that can avoid this problem in the first place?

Example; consider a 3rd party filter that decorates the output of a request and it gets an OutputStream. How is a filter or a servlet that needs to work with a Writer supposed to "know" that an OutputStream was already opened and should it care? The converse is also a valid Q.

Arjan Tijms
  • 37,782
  • 12
  • 108
  • 140
Andrew White
  • 52,720
  • 19
  • 113
  • 137

3 Answers3

2

The design approach is surprisingly easy:

  • Do not use Java code (scriptlets) in JSP. This implicitly triggers getWriter().
  • Do not write anything to the response in a Servlet when you're going to forward to a JSP.

In other words, if you adhere the MVC ideology, there's basically nothing to worry about.

BalusC
  • 1,082,665
  • 372
  • 3,610
  • 3,555
  • 1
    This is good advice, but it doesn't deal with the case where a Filter needs to modify the output produced by application. – Stephen C Jun 13 '11 at 12:56
  • @Stephen: hm, I didn't interpret the question like that. But if it is true what you thinks, it should be just a matter of adding two boolean properties and an `if` check and a boolean toggle in the both getters of the `HttpServletResponseWrapper` implementation. – BalusC Jun 13 '11 at 13:26
2

I'll attempt to address the more specific question raised in your example:

consider a 3rd party filter that decorates the output of a request and it gets an OutputStream. How is a filter or a servlet that needs to work with a Writer supposed to "know" that an OutputStream was already opened and should it care?

The Servlet API also disallows the use of both Writer and OutputStream when populating the response, as indicated in the API documentation for the ServletResponse.getWriter() method:

Either this method or getOutputStream() may be called to write the body, not both.

If a filter (third party or otherwise) wants to write to the response, especially after servlet(s) have generated it, it ought to assume that

  • the servlet has used either the Writer or the OutputStream to populate the response.
  • the servlet would have invoked the close() method on the Writer or the OutputStream object.

To account for this, the filter must create a HttpServletResponseWrapper instance, pass it downstream to the servlet for population, read it back in again, and then populate the actual container-managed HttpServletResponse object.

The above would also hold good if the filter were to populate the response first (before the request is processed further). It should perform the population on the actual HttpServletResponse object, pass a wrapper downstream, and then write the contents of the wrapper to the actual object.

Vineet Reynolds
  • 76,006
  • 17
  • 150
  • 174
0

Another approach is to design the Filter so that it uses the Writer or OutputStream depending on a configuration setting in the web.xml. Then configure the Filter according to Servlet that it is filtering requests for.

Stephen C
  • 698,415
  • 94
  • 811
  • 1,216