0

How can I parse this using Retrofit?I'm getting the error

BEGIN_OBJECT but was BEGIN_ARRAY

The Json is below and it contain a results array object, that have one array object which is null and objects of information. It seems like that array of null is the problem, and I need some help to solve this if its possible to be solved?

{
    "error": "OK",
    "limit": 100,
    "offset": 0,
    "number_of_page_results": 16,
    "number_of_total_results": "16",
    "status_code": 1,
    "results": [
        [],
        {
            "api_detail_url"............

Model class:

 public class Response {

        @SerializedName("results")
        List<IssuesResults> resultList;

        public Response(ArrayList<IssuesResults> resultList) {
            this.resultList = resultList;
        }

        public List<IssuesResults> getResultList() {
            return resultList;
        }
    }

Api

@GET("promos/")
Call<Response> getPromos(@Query("api_key") String API_KEY,
                                   @Query("format") String format);

Repo

public MutableLiveData<List<IssuesResults>> getPromos() {

    callApi.getPromos(API_KEY,"json").enqueue(new Callback<Response>() {
        @Override
        public void onResponse(Call<Response> call, 
                    retrofit2.Response<Response> response) {                   
            promosMutableData.setValue(response.body().getResultList());

        }

        @Override
        public void onFailure(Call<Response> call, Throwable t) {
            Log.d("PROMOS", "onFailure: " + t);
        }
    });

    return promosMutableData;
}
pirho
  • 11,565
  • 12
  • 43
  • 70

1 Answers1

0

I assume you use Gson with default settings. Your problem is that you expect a list of IssuesResults but it contains this extra array which means it is - by default - serializable only as a list of objects which then would be one array and N maps as items.

For this kind of stuff you need some custom handling and I present here one option which is JsonDeserializer. I requires few changes to make things a bit easier ( (they are not all necessities for other approaches but for this solution i use these ones) ). First instead of inline typed List implement class like:

@SuppressWarnings("serial")
public static class ListIssuesResults extends ArrayList<IssuesResults> {
    // This override is not needed if you do not mind null values in your resulting list
    @Override
    public boolean add(IssuesResults e) {
        if (null != e) {
            return super.add(e);
        }
        return false;
    }
}

The change the Response like:

public static class Response {
    @SerializedName("results")
    private ListIssuesResults resultList;
    // other stuff
}

Then the actual custom JsonDeserializer:

public static class IssuesResultsDeserializer implements JsonDeserializer<IssuesResults> {
    // this you need to not to cause recursion and stack overflow
    private static final Gson GSON = new Gson();
    @Override
    public IssuesResults deserialize(JsonElement json, Type typeOfT, 
            JsonDeserializationContext context)
            throws JsonParseException {
        // this is the trick. if it fails to serialize stuff like [] jsut return null
        try {
            return GSON.fromJson(json, typeOfT);
        } catch (Exception ise) {
            return null;
        }
    }
}

To use custom deserializer you need to register it like:

new GsonBuilder().registerTypeAdapter(IssuesResults.class,
    new IssuesResultsDeserializer()).create();

This has to be done in Retrofit client building phase, like in this: How to register custom TypeAdapter or JsonDeserializer with Gson in Retrofit?

pirho
  • 11,565
  • 12
  • 43
  • 70