Как обрабатывать разные схемы для ошибок в Retrofit 2? - PullRequest
0 голосов
/ 06 мая 2019

У меня есть API, который возвращает одну из следующих схем:

Успех (данные найдены)

{
    item_count: 83,
    items_per_page: 25,
    offset: 25,
    items: [
        { ... },
        { ... },
        { ... },
        ...
    ]
}

Ошибка (нетнайденные данные)

{
    success: false,
    error: {
        code: 200,
        message: "Server is busy"
    }
}

Я хочу использовать Retrofit 2 с GSON для создания оболочки вокруг этого API и преобразования в POJO, однако я не уверен, как справиться с тем фактом, что API потенциально возвращает два совершенно разныхсхемы.На данный момент у меня есть следующие классы:

public class PaginatedResponse<T> {
    private int item_count;
    private int items_per_page;
    private int offset;
    private List<T> items;

    public PaginatedResponse<T>(int item_count, int items_per_page, int offset, List<T> items) {
        this.item_count = item_count;
        this.items_per_page = items_per_page;
        this.offset = offset;
        this.items = items;
    }

    public List<T> getItems() {
        return this.items;
    }
}
public class Item {
    private int id;
    private String name;
    // ...
}

Тогда для моего интерфейса API у меня есть:

public interface API {
    @GET("items")
    Call<PaginatedResponse<Item>> getItems();
}

Затем, наконец, чтобы использовать это, я попытался сказать:

Retrofit retrofit = new Retrofit.Builder()
    .baseUrl("http://localhost")
    .addConverterFactory(GsonConverterFactory.create())
    .build();

API api = retrofit.create(API.class);

api.getItems().enqueue(new retrofit2.Callback<PaginatedResponse<Broadcast>>() {
    @Override
    public void onResponse(Call<PaginatedResponse<Broadcast>> call, Response<PaginatedResponse<Broadcast>> response) {
        Log.d("SUCCESS", response.body().getItems().toString());
    }

    @Override
    public void onFailure(Call<PaginatedResponse<Broadcast>> call, Throwable t) {
        Log.d("FAILURE", t.toString());
    }
}

Пока не выдается никаких ошибок, похоже, это работает.Но когда выдается ошибка, я получаю следующее в Logcat, и мое приложение вылетает:

java.lang.NullPointerException: Attempt to invoke virtual method 'java.lang.String java.lang.Object.toString()' on a null object reference

Похоже, что в сбое JSON отсутствует свойство items, он устанавливает List<Item> items в null

1 Ответ

1 голос
/ 07 мая 2019

Похоже, что из-за сбоя JSON отсутствует свойство items, он устанавливает элементы списка в null

Да, это так. Вы получаете NullPointerException, потому что вы вызвали toString() для нулевого объекта. Это ожидаемое поведение.

Решение

Поскольку у вас есть разные схемы для error и success, вам необходимо создать модель с обоими значениями . Ниже приведен минимальный пример,

ResponseModel.java


class ResponseModel {

    // ERROR
    private final Boolean success;
    private final Error error;

    // SUCCESS
    private final int item_count;
    // more success values... 

    ResponseModel(Boolean success, Error error, int item_count) {
        this.success = success;
        this.error = error;
        this.item_count = item_count;
    }

    public class Error {
        private final int code;
        private final String message;

        private Error(int code, String message) {
            this.code = code;
            this.message = message;
        }

        public int getCode() {
            return code;
        }

        public String getMessage() {
            return message;
        }

    }

    public Boolean getSuccess() {
        return success;
    }

    public Error getError() {
        return error;
    }

    public int getItem_count() {
        return item_count;
    }
}

и в методе onResponse вы можете проверить, является ли ответ успешным или нет, как это

ResponseModel responseModel = response.body();

if (responseModel.getError() == null) {
    // success
    doSomethingWithSuccess(responseModel.getItem_count())
} else {
    // error
    doSomethingWithError(responseModel.getError())
}
...