假设我们有这样一个json,它不能修改。
我们想用gson把它还原。

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

我们想在类中反序列化它,比如:
public class User {
    @SerializedName("some_ids")
    List<String> someIds;
}

问题是:
简单的解决方案是创建一个User包装类并将UselessKey列表放入其中。
但是,有没有办法告诉gson跳过节点someIds并直接反序列化useless_key中的列表?

最佳答案

因为您仍然需要标记一个应该以不同方式处理的字段,所以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());
}

dtoResponse类定义如下:
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>的包装类,该类甚至需要反序列化上下文将给定的JsonElement反序列化为List<String>,然后重新映射回StringIds。那太贵了。我会用类型适配器。

10-07 19:14
查看更多