考虑一下这个简单的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);
}
}
它有效,我得到了预期的输出。为什么呢?
答案 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
。也许你一直用它来做转换泥土工作。