users@jsonp.java.net

Re: JsonWriter is missing flush() method

From: Jitendra Kotamraju <jitendra.kotamraju_at_oracle.com>
Date: Thu, 31 Oct 2013 12:17:52 -0700

On 10/30/13 2:00 AM, Przemysław Bielicki wrote:
> Hi,
>
> I think, there is a serious problem with JSONP API, namely JsonWriter
> is missing flush() method.
Since there is only one write method followed by close() on JsonWriter
object, we didn't add it. It was assumed that close() would be called
which would flush the contents in case of buffering and release any
resources. One workaround would be to do:
Json.createWriter(new FilterOutputStream(servletstream) {
        public void close() throws IOException {}
});

>
> If you want to write JSON message from within the Servlet you will
> arrive to such point eventually:
>
> @Override
> protected void doGet(HttpServletRequest req, HttpServletResponse
> resp) throws IOException {
> JsonBuilderFactory bf = Json.createBuilderFactory(null);
>
> JsonObject obj = bf.createObjectBuilder().add("name", "value")
> .add("obj", bf.createObjectBuilder()
> .add("array",
> bf.createArrayBuilder().add("value").add("value2").add("value3")))
> .add("obj2", bf.createObjectBuilder().add("amount",
> "100.3")).build();
>
> JsonWriter writer = Json.createWriter(resp.getWriter());
> writer.write(obj);
> }
>
> The problem is that no message will be written to the output writer.
> It will be cached in the BufferedWriter's buffer and never flushed
> (well, depends on the buffer size, but in this particular example, no
> single byte will be flushed to the output).
That should have worked esp when you are creating JsonWriter using a i/o
Writer. JsonWriter.write() method writes all the contents to underlying
writer. The recent releases don't use BufferedWriter. Are you using the
latest version i.e. 1.3 or 1.4-SNAPSHOT ?

But if you create JsonWriter with byte stream, then that doesn't work.
Internally, it uses OutputStreamWriter(byte stream), and
OutputStreamWriter#flushBuffer() is a package private method, so the
contents are buffered in OutputStreamWriter. I am hesitant to call
OutputStreamWriter.flush() as it has side-effects like flushing the
underlying stream(for. e.g if the underlying stream is a HTTP stream, a
HTTP chunk would be written on the socket)
>
> The only way to flush the writer is to call writer.close() method. But
> it's not such a good idea because, as you recall, you should not close
> output stream inside the Servlet. Why? One of the reasons might be
> that the request is chained and some other servlets or filters might
> want to add something to the output stream later (what if you would
> like to write 10 different JSON messages to the same servlet output?).
> JSONP breaks this "contract".
>
> The solution for this would be to add flush() method to JsonWriter
> interface or to flush
You can file a bug, but this would take some time. In the mean time,
does this work ? JsonWriterImpl would implement Flushable. So an app
would need to do
JsonWriter writer = ...
if (writer instanceof Flushable) {
    ((Flushable)writer).flush();
}

Other options are override close(), or create a feature. But the best
option would be to not to do these things in the application.

> automatically the generator after write() is finished (then no
> modification to existing interfaces will be necessary).
See, above about my concern about calling flush() behind the scenes. I
will see if there is a way to avoid OutputStreamWriter and write the
contents when JsonWriter is created using byte streams.
>
> Please let me know what you think about this.
>
> Cheers,
> Przemyslaw Bielicki