Gson:如果存在某些字段,则自定义反序列化

Posted

技术标签:

【中文标题】Gson:如果存在某些字段,则自定义反序列化【英文标题】:Gson: Custom deserialization if certain field is present 【发布时间】:2013-09-03 06:14:54 【问题描述】:

我有一个如下所示的类

class Person 
    Long id;
    String firstName;
    int age;

我的输入看起来像这样:

 "id": null, "firstName": "John", "age": 10 

或者像这样:

 "id": 123 

第一个变体代表一个“新”(非持久化)人,第二个变体通过数据库 id 指代一个人。

如果id 不为空,我想在反序列化期间从数据库中加载对象,否则会退回到常规解析并将其反序列化为新对象。

我的尝试:我目前有一个 JsonDeserializer 用于数据库反序列化,但据我了解,没有办法“退回”常规解析。根据this answer,我应该使用TypeAdapterFactorygetDelegateAdapter。这种方法的问题是我得到了一个JsonReader(而不是例如JsonElement),所以我无法确定输入是否包含有效的id而不消耗输入。

关于如何解决这个问题的任何建议?

【问题讨论】:

【参考方案1】:

我不知道我是否正确理解了你的问题,但如果你已经有一个JsonDeserializer,你应该有一个像这样的方法:

public Person deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context)  ... 

在此方法中,您拥有JsonDeserializationContext 类型的对象context,它允许您对指定对象调用默认反序列化。

因此,您可以在自定义反序列化器中执行类似操作:

//If id is null...
Person person = context.deserialize(json, Person.class);

JsonDeserializationContext documentation。

【讨论】:

我尝试过这个,但由于无休止的递归,我得到了 ***Exception。我认为上下文代表“这个”gson,而不是没有这个类型适配器的这个gson。 @aioobe: 在JsonDeserializer 中创建一个新的Gson 对象并执行Person person = new Gson().fromJson(json, Person.class); 怎么样? 对,这对于我在我的问题中写的简单示例来说是可行的。但是,在我的实际代码中,我引用了其他对象(例如,假设 Person 将引用 Person parent)。如果我们将一个人的解析委托给另一个 gson 对象,则无法从数据库中加载 parent【参考方案2】:

我想我在here 上的答案的帮助下设法解决了这个问题。

这是一个工作类型的适配器工厂:

new TypeAdapterFactory() 
        @Override
        public <T> TypeAdapter<T> create(Gson gson, TypeToken<T> type) 

            final TypeAdapter<T> delegate = gson.getDelegateAdapter(this, type);
            final TypeAdapter<JsonElement> elementAdapter =
                    gson.getAdapter(JsonElement.class);

            // Are we asked to parse a person?
            if (!type.getType().equals(Person.class))
                return null;

            return new TypeAdapter<T>() 

                @Override
                public T read(JsonReader reader) throws IOException 

                    JsonElement tree = elementAdapter.read(reader);
                    JsonElement id = tree.getAsJsonObject().get("id");

                    if (id == null)
                        return delegate.fromJsonTree(tree);

                    return (T) findObj(id.getAsLong());
                

                @Override
                public void write(JsonWriter writer, T obj) throws IOException 
                    delegate.write(writer, obj);
                
            ;
        
    

我还没有完全测试它,如果需要我会回来修改它。 (现在发布它以开放以获取有关该方法的反馈。)

【讨论】:

以上是关于Gson:如果存在某些字段,则自定义反序列化的主要内容,如果未能解决你的问题,请参考以下文章

如何反序列化包含 GSON 库生成的 LocalDate 字段的 JSON

使用 gson 反序列化反序列化对象的内部对象

Gson 反序列化和序列化瞬态场

原始类型和数组的 GSON 自定义反序列化器

如何通过 gson 将 json 反序列化为嵌套的自定义地图?

使用Gson自定义反序列化到Map中