java - 使用 Gson 反序列化时跳过层次结构

标签 java android gson

假设我们有一个像这样的 json,它不能被修改。 我们希望使用 Gson 对其进行反序列化。

{
  "user": {
    "some_ids": {
      "useless_key": [
        "22a074ff-91bf-4599-9a9e-374d3f01b6e0",
        "66c8ce85-f162-4d92-a836-198a17764efa",
        "d0519a9e-bfa2-446c-bb98-746136a3e513"
      ]
    }
  }
}

我们想在类 User 中反序列化它,如下所示:

public class User {
    @SerializedName("some_ids")
    List<String> someIds;
}

问题: 简单的解决方案是创建一个 UselessKey 包装类并将 someIds 列表放入其中。

但是有没有办法告诉 Gson 跳过节点 useless_key 并直接反序列化 someIds 中的列表?

最佳答案

因为你仍然需要标记一个字段应该被不同地处理,Gson 不提供类似的东西。但是你可以实现这样的行为。最接近您要求的是 @JsonAdapter

假设你有

private static final String JSON = "{\n"
        + "  \"user\": {\n"
        + "    \"some_ids\": {\n"
        + "      \"useless_key\": [\n"
        + "        \"22a074ff-91bf-4599-9a9e-374d3f01b6e0\",\n"
        + "        \"66c8ce85-f162-4d92-a836-198a17764efa\",\n"
        + "        \"d0519a9e-bfa2-446c-bb98-746136a3e513\"\n"
        + "      ]\n"
        + "    }\n"
        + "  }\n"
        + "}";

public static void main(final String... args) {
    final Gson gson = new Gson();
    final Response response = gson.fromJson(JSON, Response.class);
    out.println(response.getUser().getSomeIds());
}

DTO Response类定义如下:

final class Response {

    private Response() { }

    @SerializedName("user")
    private final User user = null;

    User getUser() { return user; }

    static final class User {

        private User() { }

        @SerializedName("some_ids")
        @JsonAdapter(IdsTypeAdapter.class)
        private final List<String> someIds = null;

        List<String> getSomeIds() { return someIds; }

    }

}

@JsonAdapter(IdsTypeAdapter.class) 中指定的类型适配器上面可以实现如下:

final class IdsTypeAdapter
        extends TypeAdapter<List<String>> {

    private static final String USELESS_PROPERTY = "useless_key";

    private IdsTypeAdapter() {
    }

    @Override
    public void write(final JsonWriter writer, final List<String> value) {
        throw new UnsupportedOperationException();
    }

    @Override
    public List<String> read(final JsonReader reader)
            throws IOException {
        reader.beginObject();
        if ( !reader.nextName().equals(USELESS_PROPERTY) ) {
            throw new UnsupportedOperationException("Expected: " + USELESS_PROPERTY);
        }
        reader.beginArray();
        final List<String> ids = new ArrayList<>();
        while ( reader.peek() == STRING ) {
            ids.add(reader.nextString());
        }
        reader.endArray();
        reader.endObject();
        return unmodifiableList(ids);
    }

}

上面的类型适配器非常简单,并促进流读取以提高性能(@JsonAdapter 注释也需要类型适配器)。结果:

[22a074ff-91bf-4599-9a9e-374d3f01b6e0, 66c8ce85-f162-4d92-a836-198a17764efa, d0519a9e-bfa2-446c-bb98-746136a3e513]

另一种选择是使用 JSON 反序列化器(可以在 GsonBuilder 中注册),但后者会影响性能,因为它们需要在反序列化过程开始之前构建整个 JSON 树。 JSON 反序列化器的另一个问题是 Gson 不支持自定义注释,因此为了标记“特殊”字段,您仍然需要创建一个包装类,如 class StringIds extends ArrayList<String>。稍后甚至需要反序列化上下文来反序列化给定的 JsonElementList<String>然后重新映射回 StringIds .这太贵了。我会选择类型适配器。

关于java - 使用 Gson 反序列化时跳过层次结构,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/41461421/

相关文章:

java - Android中LocationListener的SettableFuture block 事件

android - Kivy 添加小部件错误

java - 如何将 GSON 的自定义可序列化方法转换为通用方法

java - 如何在 JavaFX 中的(页面、场景)之间导航

java静态实例字段和构造函数

java - Android View 中根据文件数量添加VideoView

android - viewHolder 类中的 notifyDataSetChanged

android - 通过 Gson 转换异常将 json 转换为 java 对象

java - 将 JSON 数据映射到 Java 对象时遇到问题

java - 通过 Apache Commons 上传流文件时,数据存储在哪里?