0
FATAL EXCEPTION: main Process: com.packagename, PID: 11371 java.lang.IllegalStateException: Cannot read raw response body of a converted body.

In retrofit, you can only ever read response.body() once, since it's a stream and it automatically closes once you call .string() or when it auto-converts to whatever model class you have in Response<T> return type. If you try to read twice, then you get the above error.

I need both the raw response string as well as the model class. What's the best way to do this? I do not want to make the API call twice. Is there some way to duplicate the response body? Ideally, I'd like to simply get String and T back with the response. That is, to not have to give up the generic type converter goodies that come with retrofit

Santanu Sur
  • 10,997
  • 7
  • 33
  • 52
Aditya Anand
  • 776
  • 2
  • 9
  • 29

2 Answers2

1

You could get the raw response body by adding an interceptor (https://square.github.io/okhttp/interceptors/) and copying the responsebody BufferedSource before returning the response. I'm having trouble seeing why someone would want to do this though.

Response response = chain.proceed(request);
ResponseBody responseBody = response.body();

ByteArrayOutputStream output = new ByteArrayOutputStream();
responseBody.source().getBuffer().copyTo(output);
String rawResponseBody = output.toString();

return response;
Vesper
  • 493
  • 4
  • 7
  • Yes, this gives me access to the raw response, but only within the body of the interceptor and not in the contextual place where I'm actually consuming the response (which is what I want). This would serve the use case of, e.g: Logging request bodies, but not of saving the rawResponse strings in DB as well as working with POJOs in my services. – Aditya Anand Jan 16 '20 at 08:28
  • Why not just log the responses to a DB from the server/backend endpoint that's actually sending them? The contextual place where you're consuming the response will already have converted the body. From what I can tell the only way you're going to get the rawResponse where you want it is to use Response and map the POJO yourself. – Vesper Jan 16 '20 at 08:46
  • Will explore that direction. The trouble is, I'm relying on an unreliable third party API that's frequently down and buggy. So in order to work around their erratic APIs, I need to make my system as resilient as possible in order to maximize integrity. That might mean occasionally operating on the raw responses (Which I need to have stored) and updating some other entity in my database depending on those raw responses. – Aditya Anand Jan 16 '20 at 08:54
0

example for model class:

public class Post {
    @SerializedName("text")
    private String text;
    private User   user;

    public String getText() {
        return text;
    }

    public User getUser() {
        return user;
    }
}

class User{
    @SerializedName("id")
    private int id;
    @SerializedName("name")
    private String name;

    public int getId() {
        return id;
    }

    public String getName() {
        return name;
    }
}}

for better answer: put your model class and onResponse method body in your question

Sergo Pasoevi
  • 2,833
  • 3
  • 27
  • 41
M.ghorbani
  • 129
  • 8
  • I'm not sure I see the relevance to the specific model class. The answer should not depend on the specific model and neither on the onReponse method body (what I want to do with the model after I get it). The answer to the question I'm asking precedes both of these things. – Aditya Anand Jan 15 '20 at 03:10