When working with Android or (to be more general) Apache HttpComponents, one should keep in mind that it depends on the HttpResponses (Api: Apache, Android) if they can be consumed multiple times or not. And if the response is not, then better triple check your code, what you’re doing.
I experiences the (very ugly) issue during the apparently simple task of reading the content of the response. )For ease of simplicity, I also use Apache commons-io, to read buffers etc.)
HttpResponse response = ...; String content = IOUtils.toString(response.getEntity().entity.getContent());
Okay, how many possible Nullpointer Exceptions do you see? I didn’t care until I experienced the first one, so I made the code NPE safe:
HttpEntity entity = response.getEntity(); // entity can be null according to the docs! if (entity != null) { // The interface doesn't say that getContent() MUST return non-null InputStream stream = entity.getContent(); if (stream != null) { tempContent = IOUtils.toString(entity.getContent()); } }
And suddenly I was faced with IllegalStateException: Content has been consumed
. As I also did changes somewhere else, I assumed the error in some toString()-Methods that would read the content of the response during debugging. But as the error also showed up without debugging, I had a closer look to my “improvement”.
Well, the error was the call IOUtils.toString(entity.getContent());
which tried to re-aquire the Input Stream. But as I just aquired it two lines above for the null check, the content was already marked as consumed. So the (now hopefully) correct and robust code is:
HttpEntity entity = response.getEntity(); // entity can be null according to the docs! if (entity != null) { // The interface doesn't say that getContent() MUST return non-null InputStream stream = entity.getContent(); if (stream != null) { tempContent = IOUtils.toString(<strong>stream</strong>); } }
And the moral of the story
Be very carefull when reading HttpResponses! Also avoid pretty-printing the content in toString() – this might suddenly also consume your content. And good luck finding the point where you consume the content in such cases.
But .. why?! Please avoid returning null!
Yet I still wonder, why so many methods are allowed to return null
instead of just an empty stream or something. All the Null-checks don’t make the code more readable. Some programmers might even be tempted to simply put an catch(NullPointerException e)
around the part of
response.getEntity().entity.getContent()
. Nothing I’d really recommend but I could also understand if I’d see something in other code.