Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can we handle different response type with Retrofit 2?

I have a webservice that returns either a list of serialized MyPOJO objects:

[   { //JSON MyPOJO },   { //JSON MyPOJO } ] 

either an error object :

{     'error': 'foo',    'message':'bar'  } 

Using retrofit2, how can I retrieve the error ?

Call<List<MyPOJO>> request = ... request.enqueue(new Callback<List<MyPOJO>>() {   @Override   public void onResponse(Response<List<MyPOJO>> response) {       if (response.isSuccess()) {           List<MyPOJO> myList = response.body();           // do something with the list...       } else {           // server responded with an error, here is how we are supposed to retrieve it           ErrorResponse error = ErrorResponse.fromResponseBody(apiService.getRetrofitInstance(), response.errorBody());           processError(error);           // but we never get there because GSON deserialization throws an error !       }   }    @Override   public void onFailure(Throwable t) {     if(t instanceof IOException){         // network error      }else if(t instanceof IllegalStateException){         // on server sending an error object we get there         // how can I retrieve the error object ?     }else {          // default error handling      }          } } 

Here is the GSON exception:

java.lang.IllegalStateException: Expected BEGIN_ARRAY but was BEGIN_OBJECT at line 1 column 2 path $ 

Retrofit instance is created using GsonConverterFactory

like image 589
Rémy DAVID Avatar asked Feb 23 '16 16:02

Rémy DAVID


People also ask

What is the purpose of a Retrofit interface?

Retrofit is a REST Client for Java and Android allowing to retrieve and upload JSON (or other structured data) via a REST based You can configure which converters are used for the data serialization, example GSON for JSON.


1 Answers

I had a similar issue and I solved it by using a generic Object and then testing what type of response I had using instanceof

Call<Object> call = api.login(username, password); call.enqueue(new Callback<Object>()  {     @Override     public void onResponse(Response<Object> response, Retrofit retrofit)     {          if (response.body() instanceof MyPOJO )          {             MyPOJO myObj = (MyPOJO) response.body();             //handle MyPOJO           }          else  //must be error object          {             MyError myError = (MyError) response.body();             //handle error object          }     }      @Override     public void onFailure(Throwable t)      {      ///Handle failure     } }); 

In my case I had either MyPOJO or MyError returned and I could be sure it would be one of these.

In other cases then I had the backend return the same Response Object no matter if the request was successful or not.
Then inside this response object I had my actual data within an "Object" field. Then I can use instance of to determine what type of data I had. In this case I always had the same object being returned, no matter what the call was.

public class MyResponse {      private int responseCode;     private String command;     private int errorno;     private String errorMessage;     private Object responseObject;   //This object varies depending on what command was called     private Date responseTime; } 
like image 192
jason.kaisersmith Avatar answered Sep 21 '22 09:09

jason.kaisersmith