Hey guys
I had to do something like response.body().bytes() in an Interceptor, then had to recreate a full Response with the fetched byte to return a clean Request that can be parsed again, instead of just switching the Reader Index back to it's beginning. That's a lot of temporary objects to garbage-collect.
Do you have a better solution?
You can call .peekBody(Long.MAX_VALUE) to buffer the entire response in memory and get a lightweight copy of it. It'll be much less wasteful.
That's a lot of temporary objects to garbage-collect.
It's only one temporary object, the byte[]. Everything else is pooled automatically.
Switching to peekBody saves that allocation but you still copy the underlying data between pooled objects. To eliminate copying skip peekBody and get the BufferedSource of the response, call request(Long.MAX_VALUE) to buffer the entire response data, and then call .snapshot() to get a read-only copy as a ByteString (which is less convenient to read from incrementally but perfectly fine if you just want raw data). This does no storage allocation (aside from the objects wrapping the data) or data copies.
So basically, it would look like this?
final BufferedSource source = response.body().source();
source.request(Integer.MAX_VALUE);
final byte[] bytes = source.buffer().snapshot().toByteArray();
Will this solution also work with multipart requests?
Yep! Although your toByteArray() is going to still allocate a byte[] and do a data copy. Can you read what you need directly from ByteString?
I'm using Jackson's ObjectMapper readValue that can accepts both a byte[] or a String.
Should I simply call snapshot().utf8() ?
internalArray() is package-protected
That will give you a read-only view of the bytes without a copy, yes.
Awesome, thanks a lot for your support!
Most helpful comment
I'm using Jackson's ObjectMapper
readValuethat can accepts both abyte[]or aString.Should I simply call
snapshot().utf8()?internalArray()is package-protected