使用Gson进行反序列化时跳过层次结构

时间:2017-01-04 10:21:09

标签: java android gson

假设我们有一个像这样的json,无法修改。 我们希望使用Gson对它进行去除。

arrayPtr = *array;

我们希望在类{ "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列表放入其中。

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

2 个答案:

答案 0 :(得分:0)

由于你仍然需要标记一个应该以不同方式处理的字段,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不支持自定义注释,因此为了标记&#34; special&#34;您仍然需要创建一个包含类class StringIds extends ArrayList<String>的字段,以后甚至需要反序列化上下文将给定的JsonElement反序列化为List<String>,然后重新映射回StringIds。这很贵。我会选择类型适配器。

答案 1 :(得分:-1)

不要在Model类中创建变量和getter以及setter。然后它不会解析未找到的密钥。