GSON - 反序列化原始数组

时间:2015-04-28 19:36:49

标签: java json gson deserialization

考虑一下这个简单的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);
    }
}

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

2 个答案:

答案 0 :(得分:4)

让我们将您的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状态

  

在指定对象上调用默认反序列化。这应该   永远不会在作为参数接收的元素上调用   JsonDeserializer.deserialize(JsonElement, Type, JsonDeserializationContext)方法。这样做会导致   无限循环,因为Gson将转而调用自定义反序列化器   试。

所以,即使它有效,你也很可能会有一个堆栈溢出。

那为什么不起作用?

你打电话(伪代码)

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);

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

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

支持开箱即用,并会按预期返回带有两个元素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);

答案 1 :(得分:0)

好吧,看看你想要的ArrayDeserializer类的版本:

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,因此在第二次通话时,您将没有数组......这就是您拥有{{1}的原因}。

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