1

I'm doing a mobile application in Android/Java and I'm doing a few HTTP requests using Retrofit, RxJava and RxAndroid.

In one of those HTTP request, I have declared my model class to expect a response like this:

{
   "code":201,
   "message":"Successfully",
   "data":{
      "devices":[
         {
            "state":"OK",
            // ... a few more properties
         }
      ]
   }
}

There is a scenario where the same HTTP request return a different body, like this:

{
   "code":201,
   "message":"Successfully",
   "data":{
      "devices":"" // <= is not an array anymore, it's just an empty string
   }
}

Due to this difference in the response body I received the following error:

android Expected BEGIN_ARRAY but was STRING

I was thinking in a way to convert that empty string to an empty array to avoid the error, at least an empty array matches my model class.

My models:

public class FullResponse {
    @SerializedName("code")
    private int code;
    @SerializedName("message")
    private String message;
    @SerializedName("data")
    private FullData data;

    // Constructor
    // Getters & Setters
}

public class FullData {

    private List<Device> devices;

    // Constructor
    // Getters & Setters
}

public class Device {

    private String state;
    // ... a few more properties

    // Constructor
    // Getters & Setters
}

Interface of endpoints:

public interface ApiService {

    @FormUrlEncoded
    @POST("/status.php")
    Observable<FullResponse> getStatus(@HeaderMap Map<String, String> headers, @FieldMap Map<String, String> request);

}

Doing the request:

public class Request extends BaseRequest {

    private Map<String, String> requestData;
    private FullRequestSubscriber mStatusFullSubscriber;

    // Constructor

    @Override
    public void request() {
        HashMap<String, String> headers = new HashMap<>();
        headers.put("Content-Type", "application/x-www-form-urlencoded");

        if (mStatusFullSubscriber != null) {
                apiService
                        .getStatus(headers, requestData)
                        .subscribeOn(Schedulers.io())
                        .observeOn(AndroidSchedulers.mainThread())
                        .subscribe(mStatusFullSubscriber);
            }

        mStatusFullSubscriber.addToCompositeSubscription();

    }
}

Subscriber:

public class FullRequestSubscriber extends BaseSubscriber<FullResponse> {

    private FullResponse response;
    private Context mContext;
    private OnSubscriptionInteractionListener subscriptionListener;
    private OnRequestInteractionListener interactionListener;

    // Constructor

    @Override
    public void onStart() {
        this.response = null;
        super.onStart();
    }

    @Override
    public void onCompleted() {
        super.onCompleted();
        this.interactionListener.onRequestResponse(this.response);
    }

    // Error received here: android Expected BEGIN_ARRAY but was STRING
    @Override
    public void onError(Throwable e) {
        //super.onError(e);
        getSubscriberListener().removeSubscriber(this);

        if (requireLoading()) {
            ((BaseActivity) getContext()).hideLoading();
        }

        this.interactionListener.onRequestError();
    }

    @Override
    public void onNext(FullResponse o) {
        this.response = o;
    }

    @Override
    protected Context getContext() {
        return this.mContext;
    }

    @Override
    protected Class<?> getErrorResponseType() {
        return null;
    }

    @Override
    protected OnSubscriptionInteractionListener getSubscriberListener() {
        return this.subscriptionListener;
    }

    public interface OnRequestInteractionListener {
        void onRequestResponse(FullResponse data);
        void onRequestError();
    }
}

I'm not sure where and how can I do the conversion to fix the error.

My goal is to convert the empty string to an empty array to avoid the error and to maintain a matching model.

1 Answer 1

0

I have encountered this issue before. Do you have control over the response? The best solution I found was having the BE send a Null value instead of a String. Retrofit is awesome, but asking it to cast to different object types conditionally is kind of gross.

..but if you really wanted to do it, it looks like you could make private List<Device> devices; into private JSONObject devices; and manually cast things as you please. Reference Retrofit multiple response types

edit try adding a serializedName to FullData for its devices:

public class FullData {

    @SerializedName("devices")
    private List<JSONObject> devices;

    // Constructor
    // Getters & Setters
}
Sign up to request clarification or add additional context in comments.

1 Comment

I did your advice but, the HTTP request still goes to the onError method. How can I do to receive the response on the onCompleted() method? maybe setting JSONObject as the return type everywhere?

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.