Ожидался BEGIN_OBJECT, но был BEGIN_ARRAY с модернизацией

Как я могу разобрать это с помощью Retrofit? Я получаю сообщение об ошибке

BEGIN_OBJECT, но было BEGIN_ARRAY

Json находится ниже и содержит объект массива результатов, который имеет один объект массива, который имеет значение NULL, и объекты информации. Кажется, проблема заключается в массиве null, и мне нужна помощь, чтобы решить эту проблему, если ее можно решить?

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

Класс модели:

 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);

Репо

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;
}

person de_androID    schedule 28.12.2019    source источник


Ответы (1)


Я предполагаю, что вы используете Gson с настройками по умолчанию. Ваша проблема в том, что вы ожидаете, что список IssuesResults, но он содержит этот дополнительный массив, что означает, что он - по умолчанию - сериализуемый только как список объектов, который тогда будет одним массивом и N картами как элементы.

Для такого рода вещей вам потребуется некоторая индивидуальная обработка, и я представляю здесь один вариант - JsonDeserializer. Мне нужно внести несколько изменений, чтобы немного упростить задачу ((это не все, что нужно для других подходов, но для этого решения я использую эти)). Сначала вместо встроенного типизированного List реализуйте класс, например:

@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;
    }
}

Изменение Response как:

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

Потом собственно кастом 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;
        }
    }
}

Чтобы использовать собственный десериализатор, вам необходимо зарегистрировать его, например:

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

Это необходимо сделать на этапе создания клиента модернизации, как показано ниже: Как зарегистрировать пользовательский адаптер TypeAdapter или JsonDeserializer с помощью Gson в модернизации?

person pirho    schedule 28.12.2019