GSON - 反序列化原始数组

GSON - Deserialize primitive array

考虑这个简单的问题 Json:

{
    "test": [
        0,
        3
    ]
}

现在我想在一个简单的 int 数组中反序列化它,为此我使用自定义反序列化器:

class ArrayDeserializer implements JsonDeserializer<int[]> {
    @Override
    public int[] deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException {
        return context.deserialize(json.getAsJsonObject().getAsJsonArray("test"), int[].class);
    }
}

然后:

Gson gson = new GsonBuilder().registerTypeAdapter(int[].class, new ArrayDeserializer()).create();
int[] arr = gson.fromJson(json, int[].class);

抛出:

Exception in thread "main" com.google.gson.JsonSyntaxException: java.lang.IllegalStateException: Not a JSON Object: [0,3]

但是当我这样做时:

class ArrayDeserializer implements JsonDeserializer<int[]> {

    private static final Gson gson = new Gson();

    @Override
    public int[] deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException {
        return gson.fromJson(json.getAsJsonObject().getAsJsonArray("test"), int[].class);
    }
}

它有效,我得到了预期的输出。为什么?

嗯,看看你想要的 ArrayDeserializer 版本 class:

class ArrayDeserializer implements JsonDeserializer<int[]> {
    @Override
    public int[] deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException {
        return context.deserialize(json.getAsJsonObject().getAsJsonArray("test"), int[].class);
    }
}

deserialize 方法中你再次调用 deserialize,所以在第二次调用时,你不会有一个数组...这就是为什么你有一个 IllegalStateException.

您的方法应该创建一个 int[] 数组(具有适当的转换),然后 return 它。这就是为什么你的第二个版本 gson.fromJson 有效,因为 fromJson 反序列化为 int[]。也许你一直用它来做转换的污垢工作。

让我们将您的 ArrayDeserializer 重写为等效但更具表现力的形式

class ArrayDeserializer implements JsonDeserializer<int[]> {
    @Override
    public int[] deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException {
        JsonArray jsonArray = json.getAsJsonObject().getAsJsonArray("test");
        return context.deserialize(jsonArray, int[].class);
    }
}

JsonDeserializationContext#deserialize javadoc 声明

Invokes default deserialization on the specified object. It should never be invoked on the element received as a parameter of the JsonDeserializer.deserialize(JsonElement, Type, JsonDeserializationContext) method. Doing so will result in an infinite loop since Gson will in-turn call the custom deserializer again.

所以,即使它成功了,你也很可能手上有一个 Whosebug。

那么为什么它不起作用?

您调用了(伪代码)

deserialize {test:[0,3]} as int[]
// --> Gson finds ArrayDeserializer mapped to int[]
take given JSON as an object (OK), extract 'test' as JSON array (OK)
deserialize [0,3] as int[]
// --> Gson finds ArrayDeserializer mapped to int[]
take given JSON as an object (FAIL)

你上次重复出现时,JSON 已经是 JSON 数组的形式,但你的 ArrayDeserializer 需要一个 JSON 对象。

第二次尝试

return gson.fromJson(json.getAsJsonObject().getAsJsonArray("test"), int[].class);

您再次提取 'test' JSON 数组并将其提供给您尚未注册 ArrayDeserializer 的新 Gson 实例。实际上,您正在调用

new Gson().fromJson("[0,3]", int[].class);

这是开箱即用的支持,将 return 一个带有两个元素 0 和 3 的 int[],正如预期的那样。


有更简单的解决方案。

定义一个简单的 POJO 类型

class Pojo {
    private int[] test;
    public int[] getTest() {
        return test;
    }
    public void setTest(int[] test) {
        this.test = test;
    }
}

并反序列化它

Pojo pojo = new Gson().fromJson(json, Pojo.class);
int[] arr = pojo.getTest(); 

Gson gson = new Gson();
JsonArray jsonArray = gson.toJsonTree(json).getAsJsonObject().get("test").getAsJsonArray();
int[] arr = gson.fromJson(jsonArray, int[].class);