46

I am testing Retrofit to compare it with Volley and I am struggling to get the response from my requests. For example, I do something like this:

RestAdapter restAdapter = new RestAdapter.Builder()
            .setEndpoint("http://localhost:8080")
            .build();

MyService service = restAdapter.create(MyService.class);
service.getToto("toto", new Callback<Toto>() {

        @Override
        public void success(Toto toto, Response response) {
            // Try to get response body
            BufferedReader reader = null;
            StringBuilder sb = new StringBuilder();
            try {
                reader = new BufferedReader(
                    new InputStreamReader(response.getBody().in()));
                String line;
                try {
                    while ((line = reader.readLine()) != null) {
                        sb.append(line);
                    }
                } catch (IOException e) {
                    e.printStackTrace();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
            String result = sb.toString();
        }

        @Override
        public void failure(RetrofitError error) {}
    });

It works, the object toto is set, but for testing purposes, I also want to display the JSON response returned by the server.

So I am trying to read the InputStream from response.getBody() which is a TypedInputStream. Unfortunately, I always get an IOException : Stream is closed.

I tried to use the Utils class from Retrofit but I get the same IOException error.

JJD
  • 50,076
  • 60
  • 203
  • 339
Kerwan
  • 1,188
  • 1
  • 9
  • 12
  • I think that you can use custom Converter to delegate parsing to real converter and log server's response [More info here](http://stackoverflow.com/a/22820153/1308475) – lordmegamax Apr 02 '14 at 18:59
  • im having the same issue. similarly simple setup, my actual custom response object is fine, populated and whatnot, but when i try and grab the inputstream from the response directly, same error. but response inputstream in `failure()` works fine – trippedout Apr 10 '14 at 18:21
  • actually just noticed something weird. when i turned on logging in retrofit, and it spits out all the info i want to see anyway, my inputstream consuming works fine, no error thrown. weirdd... – trippedout Apr 10 '14 at 20:03
  • @trippedout see my answer below... – droppin_science Jan 12 '15 at 16:47
  • you can use `JsonObject` as response, then get your `String` from `josnObject.toString()` – Mohammad Ersan Feb 09 '15 at 16:22

9 Answers9

53

Inside callback's angle brackets write "Response" and then extract the stream from this response.

service.getToto("toto", new Callback<Response>() {
    @Override
    public void success(Response result, Response response) {

        //Try to get response body
        BufferedReader reader = null;
        StringBuilder sb = new StringBuilder();
        try {

            reader = new BufferedReader(new InputStreamReader(result.getBody().in()));

            String line;

            try {
                while ((line = reader.readLine()) != null) {
                    sb.append(line);
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        } catch (IOException e) {
            e.printStackTrace();
        }


        String result = sb.toString();
    }

    @Override
    public void failure(RetrofitError error) {

    }
});
Nitesh Kumar
  • 5,370
  • 5
  • 37
  • 54
  • @Kerwan If this answer helped you, kindly select this answer and up vote it so that it can help others as well – Nitesh Kumar Jun 25 '14 at 06:14
  • Yes thank you ! I forgot about my question, I used Volley instead but your solution works :) – Kerwan Jul 02 '14 at 08:58
  • If I follow your approach, I get an error: **retrofit.RetrofitError: No Retrofit annotation found. (parameter #2)** – IgorGanapolsky Apr 30 '15 at 16:44
  • @IgorGanapolsky Try my other answer. May be that will help you. Link http://stackoverflow.com/questions/23853552/retrofit-sending-post-request-to-server-in-android/24550953?noredirect=1#comment48091580_24550953 – Nitesh Kumar May 02 '15 at 06:43
  • 1
    @NiteshKhatri My main problem was specifying a data type and a callback in an RXJava observable. Retrofit only returns one callback as far as RXJava is concerned (observable). So I just introspect the Retrofit Response now as the sole return type, and the problem goes away. – IgorGanapolsky May 03 '15 at 14:51
  • When you say add a "Response" object in the Callback's angle bracket, that requires changing the @POST request parameters. Do you use the Response from com.squareup.okhttp or Retrofit.client? I am having an issue which I posted in the following: http://stackoverflow.com/questions/35068601/how-to-handle-jsonsyntaxexception-when-receiving-response-from-gae – tccpg288 Jan 28 '16 at 18:41
  • I have been looking for the answer for ages, somehow I i haven't found it. thanks. it is working perfectly. – bheatcoker Apr 14 '16 at 14:25
29

Before Retrofit 2.0

   String bodyString = new String(((TypedByteArray) response.getBody()).getBytes());

Retrofit 2.0

 String  bodyString = new String(response.body().bytes());
Arpit Patel
  • 7,212
  • 5
  • 56
  • 67
shiami
  • 7,174
  • 16
  • 53
  • 68
23

If you set .setLogLevel(RestAdapter.LogLevel.FULL) on the RestAdapter that you use to create the service you should get the raw JSON response output in the debug console.

RestAdapter restAdapter = new RestAdapter.Builder()
    .setServer("http://my_lovely_api.com")
    .setLogLevel(RestAdapter.LogLevel.FULL)
    .build();

mService = restAdapter.create(MyService.class);

If you want to do something different with this raw response you can still use the code you have in your success block to create a JSON string assuming that you keep the LogLevel.FULL in the setLogLevel method, if not then it won't parse the InputStream from response.getBody().in() as it's already been read and closed.

droppin_science
  • 481
  • 4
  • 14
  • Great! .setLogLevel(RestAdapter.LogLevel.FULL) helps me – kaitian521 Sep 07 '15 at 06:35
  • this is useful only when your app is running in DEBUG. it is a good solution especially since we dont want to log in release builds. I unfortunately had to write logs in a release build. So, this solution doesnt work in such cases. I am using retrofit 1.9 – techtinkerer Apr 06 '17 at 07:00
3

I recently encountered a similar problem. I wanted to look at some json in the response body but didn't want to deal with the TypedByteArray from Retrofit. I found the quickest way to get around it was to make a Pojo(Plain Old Java Object) with a single String field. More Generally you would make a Pojo with one field corresponding to whatever data you wanted to look at.

For example, say I was making a request in which the response from the server was a single string in the response's body called "access_token"

My Pojo would look like this:

public class AccessToken{
    String accessToken;

    public AccessToken() {}

    public String getAccessToken() {
        return accessToken;
    }
} 

and then my callback would look like this

Callback<AccessToken> callback = new Callback<AccessToken>() {
   @Override
   public void success(AccessToken accessToken, Response response) {
       Log.d(TAG,"access token: "+ accessToken.getAccessToken());
   }

   @Override
   public void failure(RetrofitError error) {
       Log.E(TAG,"error: "+ error.toString());
   }
};

This will enable you to look at what you received in the response.

Michael Alan Huff
  • 3,462
  • 3
  • 28
  • 44
3

Please, don't use streams and straemReaders for this. Use smart solutions like square does:

private Response logAndReplaceResponse(String url, Response response, long elapsedTime)

http://www.programcreek.com/java-api-examples/index.php?source_dir=retrofit-jaxrs-master/retrofit/src/main/java/retrofit/RestAdapter.java

example:

private String getResponseBody(Response response) {
    String result = "";
    //Try to get response body
    if (response.getBody() instanceof TypedByteArray) {
        TypedByteArray b = (TypedByteArray) response.getBody();
        result = new String(b.getBytes());
    }
    return result;
}
Kirill Vashilo
  • 1,559
  • 1
  • 18
  • 27
1

Another solution would be to do something like the following:

  private static String bodyAsString(RequestBody body) {
    try {
      Buffer buffer = new Buffer();
      body.writeTo(buffer);
      return buffer.readString(body.contentType().charset());
    } catch (IOException e) {
      throw new RuntimeException(e);
    }
  }

Taken from https://github.com/square/okhttp/blob/master/okcurl/src/test/java/com/squareup/okhttp/curl/MainTest.java#L93-L101

loeschg
  • 29,961
  • 26
  • 97
  • 150
1

With version 2.1.0, you can get the content as

public void onResponse(Call<T> call, Response<T> response) {
    String errorString = response.errorBody().string();
}
Ravi Selvaraj
  • 547
  • 6
  • 12
0

Just do it like this:

ModelClass modelclass=response.response.body()
System.out.println("****************-----retro rsp----1-------"+modelclass.getMessage());
Floern
  • 33,559
  • 24
  • 104
  • 119
Nishanth S Babu
  • 290
  • 3
  • 11
-1

in your model of response press cmd+n and override "toString" method and only call as response.toString();

@Override
public String toString() {
    return "{" +
            "key_one='" + var_keyone + '\'' +
            ", key_two='" + var_keytwo + '\'' +
            '}';
}
Osvaldo Bringaz
  • 127
  • 1
  • 7