Мне нужно не возвращать массив с null
элементами после разбора ответа от Web Service
, но я не могу понять, как настроить Gson
для этого. Я намеревался сделать это таким образом, поскольку мне не нравится обрабатывать проанализированный ответ (необходимость повторять цикл снова).
Позвольте мне показать вам базовый пример того, что я имею в виду.
Учитывая это POJO
:
public class Item {
@SerializedName("_id")
private String id; // Required field
private String name;
@SerializedName("accept_ads")
private boolean acceptAds;
// Getters and setters
}
И получил JSON
ответ от веб-службы:
[
{"_id": "a01",
"name": "Test1",
"accept_ads": true},
{"name": "Test2"}
]
Я создал этот десериализатор:
public class ItemDeserializer implements JsonDeserializer<Item> {
@Override
public Item deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException {
Item item = null;
JsonObject jsonObject = json.getAsJsonObject();
if (jsonObject.has("_id")) {
item = new Item();
item.setId(jsonObject.get("_id").getAsString());
if (jsonObject.has("name")) {
item.setName(jsonObject.get("name").getAsString());
}
if (jsonObject.has("accept_ads")) {
item.setAcceptAds(jsonObject.get("accept_ads").getAsBoolean());
}
}
return item;
}
}
Затем я создаю мои Gson
и Retrofit
экземпляры, подобные этому:
Gson gson = new GsonBuilder().registerTypeAdapter(Item.class, new ItemDeserializer()).create();
mRetrofit = new Retrofit.Builder().addConverterFactory(GsonConverterFactory.create(gson)).build();
К сожалению, возвращаемое ArrayList<Item>
содержит значения Item
и null
.
UPATE
Благодаря @ deluxe1 в комментариях ниже я прочитал связанный поток SO , который сам по себе не то, что я искал, так как речь идет о сериализаторах, а не о десерализаторах. , Однако другой ответ в этой теме специально посвящен десериализаторам.
К сожалению, я не могу заставить его работать. Обратите внимание, что в этом случае речь идет о нулевых элементах JsonElements внутри ответа JSON HTTP body, а это не совсем то, чего я пытаюсь достичь. В моем случае JsonElement может быть не нулевым, но в нем отсутствуют обязательные поля, что в итоге делает его недействительным (следовательно, нулевым).
Учитывая приведенные выше примеры классов, я создал следующий десериализатор:
public class NonNullListDeserializer<T> implements JsonDeserializer<List<T>> {
@Override
public List<T> deserialize(JsonElement json, Type typeOfT, JsonDeserializationcontext context) throws JsonParseException {
Gson gson = new GsonBuilder().create();
List<T> items = new ArrayList<>();
for (final JsonElement jsonElement : json.getAsJsonArray() {
T item = gson.fromJson(jsonElement, typeOfT);
if (item != null) {
items.add(item);
}
}
return items;
}
}
Конечно, я не забыл зарегистрировать его как TypeAdapter в Gson.
Дело в том, что typeOfT
равно java.util.ArrayList<com.example.Item>
, когда этот метод вызывается (но почему ??). В результате строка T item = gson.fromJson(jsonElement, typeOfT)
не вызывается с внутренним классом (в данном случае Item), вызывая это исключение:
com.google.gson.JsonSyntaxException: java.lang.IllegalStateException: Expected BEGIN_ARRAY but was BEGIN_OBJECT at path $
AFAIK, стирание типа делает невозможным следующее:
T item = gson.fromJson(jsonElement, T.class)