[2.2.1] Multiple calls to WS.Response.asJson() results in exception #2096

torbinsky opened this Issue Nov 26, 2013 · 14 comments


None yet
10 participants

Basically, it looks like the WS.Response Json parser is consuming a stream each time a call to asJson() is made, so more than one call results in an attempt to read and parse an empty stream. It seems that it should only read from the stream once and store that result so that it can return it in subsequent calls to asJson().

The exception being encountered:

java.lang.RuntimeException: com.fasterxml.jackson.databind.JsonMappingException: No content to map due to end-of-input

Reproduction code:

    public static void main(String[] args){
        WS.url("http://api.openweathermap.org/data/2.5/weather?q=London,uk").get().flatMap(new Function<WS.Response, F.Promise<String>>() {

            public Promise<String> apply(Response a) throws Throwable {
                System.out.println(a.asJson()); // prints fine
                System.out.println(a.asJson()); // throws exception
                return null;
        }).recover(new Function<Throwable, String>() {
            public String apply(Throwable throwable) throws Throwable {
                return null;

huntc commented Nov 26, 2013

Thanks! What'd think @wsargent ?


jroper commented Nov 27, 2013

Interesting question about what should be the correct behaviour here. The WS API parses the body lazily when requested. It doesn't cache the result. Considering that the body of an HTTP response is a stream, and not something that you want to necessarily buffer in memory, then it makes sense that accessing the body twice (regardless of what format you are accessing the body in) would not be supported. Imagine this:


What would you expect the second call to return? An empty stream? I'd expect either an empty stream, or an exception saying you can't consume the body twice. What about this:


Again, I'd expect either an exception, or an empty byte array, since the body has already been consumed via the streaming JSON parser, it's not possible to access it a second time. So, for consistency, I think having two calls to asJson being illegal as well makes sense.

What is probably needed here is documentation to say that all the as* methods consume the body, and that it's illegal to consume the body twice.


hepin1989 commented Nov 27, 2013

@torbinsky Hi,we are using Play java two,and so does the play-ws,the asJson call will consume the response body as an stream,so after the first call,the second call will be an empty stream.You could look the WS's source code


wsargent commented Nov 27, 2013

I think @jroper is correct, we can only consume the stream once -- but asJson() implies that it can be called repeatedly (while getBodyAsStream() is just redundant, as it can hardly stream anything else). An API that showed response.stream().asJson() or response.stream().asByteArray() would be far clearer, as a stream is transient.

Given the examples that @jroper provided it does seem that it would be a bit inconsistent to have the as*() methods consume and then cache a response body while there are other methods that wouldn't. I don't think the API makes it clear that these are stream operations though, so documentation is definitely needed as it is really not obvious that these methods are stream operators. I think the API described by @wsargent would be one step better and makes it much more clear that as*() methods are stream operations.

Given that the previous versions allowed multiple calls, I would guess that the WS Response API wasn't originally designed with this in mind which might be why it wasn't set up to more clearly reflect the streaming nature it now has.


huntc commented Nov 27, 2013

I agree with @wsargent that a new stream() method would make this nice and clear. as* and to* methods don't normally consume streams by convention.


jroper commented Nov 28, 2013

I think stream().asJson() might be a bit confusing, implying that it's a stream of JSON. Perhaps parseAsJson() is better, because the parse verb here implies that we are doing something. Or consumeAsJson().

hadesara commented Jan 8, 2014

I had to pull my hairs coz of this recently. I think consistency is important. And because stream and other types can only be read once, we should stick with reading it only once. However, returning an empty byte stream with reading the next time might be confusing. Instead of that, may be you can return End of stream exception so that the user would know that it is already read once and also that it can be consistent across other types.


jroper commented Jan 9, 2014

@hadesara There is no EndOfStreamException in Java. If you read from an InputStream once it has reached the end of stream, it just keeps returning empty arrays. So in fact that this is consistent with the way Java handles InputStream at least, to diverge from that would be to be inconsistent.

hadesara commented Jan 9, 2014

How about EOFException ?

Glad you opened this issue. The docs/API don't make this clear, finding this ticket saved us a few hours of headache.

aelex13 commented Mar 6, 2014

Thanks to this issue i found that my error was caused by multiple calls to the WS.Response.asJson() method. I would really recommend updating the docs on the asJson() method to prevent other people from running into a bug that is completely preventable by just calling the asJson() once.

maybe should rename like stack popJson...
remember update / correct the doc here too..


cchantep commented Aug 31, 2016

Closing it for now. Can be reopened or a new ticket added about if new inputs

cchantep closed this Aug 31, 2016

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment