简体   繁体   English

GSON - 反序列化原始数组

[英]GSON - Deserialize primitive array

Consider this simple Json: 考虑一下这个简单的Json:

{
    "test": [
        0,
        3
    ]
}

Now I want to deserialize it in a simple int array so for that I use a custom deserializer: 现在我想在一个简单的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);
    }
}

and then: 然后:

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

which throws: 抛出:

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

However when I do this: 但是当我这样做时:

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

it works and I get the expected output. 它工作,我得到预期的输出。 Why? 为什么?

Let's rewrite your ArrayDeserializer in to an equivalent form but more expressive 让我们将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);
    }
}

The JsonDeserializationContext#deserialize javadoc states 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. 永远不应该在作为JsonDeserializer.deserialize(JsonElement, Type, JsonDeserializationContext)方法的参数接收的元素上调用它。 Doing so will result in an infinite loop since Gson will in-turn call the custom deserializer again. 这样做会导致无限循环,因为Gson会再次调用自定义反序列化器。

So, even if it had worked, you'd more than likely have a stackoverflow on your hands. 所以,即使它有效,你很可能会有一个堆栈溢出。

So why didn't it work? 那么为什么它不起作用?

You called (in pseudo-code) 你叫(伪代码)

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)

This last time you recurred, the JSON was already in the form of a JSON array but your ArrayDeserializer was expecting a JSON object. 上一次你再次出现时,JSON已经是JSON数组的形式,但你的ArrayDeserializer期待一个JSON对象。

In your second attempt 在你的第二次尝试

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

you're again extracting the 'test' JSON array and feeding it to a new Gson instance on which you haven't registered your ArrayDeserializer . 你再次提取' ArrayDeserializer数组并将它提供给你尚未注册ArrayDeserializer的新Gson实例。 In effect, you're invoking 实际上,你正在调用

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

which is supported out of the box and will return an int[] with the two elements 0 and 3, as expected. 它是开箱即用的,并将返回一个带有两个元素0和3的int[] ,如预期的那样。


There are simpler solutions. 有更简单的解决方案。

Define a simple POJO type 定义一个简单的POJO类型

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

and deserialize to it 并反序列化它

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

Or 要么

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

Well, looking at your desired version of ArrayDeserializer class: 好吧,看看你想要的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);
    }
}

Inside deserialize method you are calling again deserialize , so at the second call, you'll not have an array... that is the reason why you have an IllegalStateException . deserialize方法中你再次调用deserialize ,所以在第二次调用时,你将没有数组......这就是你有一个IllegalStateException的原因。

Your method should create an int[] array (with the appropriate convertions) and then return it. 您的方法应该创建一个int[]数组(具有适当的转换),然后返回它。 That's why your second version, with gson.fromJson works, because fromJson deserializes to int[] . 这就是为什么你的第二个版本, gson.fromJson工作,因为fromJson反序列化为int[] Maybe you keep using this to do the converting dirt work. 也许你继续用它来做转换污垢的工作。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM