【问题标题】:Avoid adding null POJO objects to parsed array from retrofit response避免从改造响应将空 POJO 对象添加到解析数组
【发布时间】:2019-08-01 21:29:41
【问题描述】:

在解析来自Web Service 的响应后,我需要避免返回带有null 项的数组,但我不知道如何配置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;
  }

}

然后,我创建我的 GsonRetrofit 实例,如下所示:

Gson gson = new GsonBuilder().registerTypeAdapter(Item.class, new ItemDeserializer()).create();

mRetrofit = new Retrofit.Builder().addConverterFactory(GsonConverterFactory.create(gson)).build();

不幸的是,返回的ArrayList&lt;Item&gt; 包含Itemnull 值。

更新

感谢@deluxe1 in the comments below,我阅读了linked SO thread,它本身并不是我想要的,因为它是关于序列化器而不是解序列化器的。但是,该线程中的另一个答案专门针对反序列化器。

很遗憾,我无法让它工作。请注意,在这种情况下,JSON HTTP 正文响应中的 JsonElements 为空,这并不是我想要实现的。在我的例子中,一个 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;

  }
}

当然,我记得在 Gson 中注册为 TypeAdapter。

问题是,当调用该方法时,typeOfTjava.util.ArrayList&lt;com.example.Item&gt;(但为什么呢??)。结果,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)

【问题讨论】:

  • 您在 JSON 中缺少一个 "-char:"a01, 如果这是您真正返回的内容,您应该先修复它。
  • @vilpe89 谢谢,我已经更新了这个例子,因为这只是我这边的一个错字。另外,请注意,提供的 JSON 只是解释我的问题的一个简单示例。从 web 服务返回的 JSON 格式也很完美。
  • 看看这个问题和接受的答案stackoverflow.com/a/29733208/9464051
  • @UnaDeKalamares,deluxe1 的链接对您有帮助吗?您还需要其他建议吗?
  • 我正在审查那个答案,这似乎指向了正确的方向,但似乎不起作用。我将更新我的问题以包含更多信息。谢谢!

标签: android gson retrofit


【解决方案1】:

NonNullListDeserializer 需要稍作修改:

class NonNullListDeserializer<T> implements JsonDeserializer<List<T>> {

    @Override
    public List<T> deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException {
        if (json instanceof JsonArray) {
            final JsonArray array = (JsonArray) json;
            final int size = array.size();
            if (size == 0) {
                return Collections.emptyList();
            }
            final List<T> list = new ArrayList<>(size);
            for (int i = 0; i < size; i++) {
                // get element type
                Type elementType = $Gson$Types.getCollectionElementType(typeOfT, List.class);
                T value = context.deserialize(array.get(i), elementType);
                if (value != null) {
                    list.add(value);
                }
            }

            return list;
        }

        return Collections.emptyList();
    }
}

现在,您需要反序列化您的 JSON 有效负载,如下所示:

Gson gson = new GsonBuilder()
        .registerTypeAdapter(Item.class, new ItemDeserializer())
        .registerTypeAdapter(List.class, new NonNullListDeserializer<>())
        .setPrettyPrinting()
        .create();

Type itemListType = new TypeToken<List<Item>>() {}.getType();
List<Item> response = gson.fromJson(json, itemListType);

【讨论】:

    猜你喜欢
    • 2021-12-09
    • 1970-01-01
    • 1970-01-01
    • 2015-09-04
    • 2018-10-18
    • 1970-01-01
    • 2015-08-18
    • 2021-03-15
    • 1970-01-01
    相关资源
    最近更新 更多