【问题标题】:Gson serialize interface / abstract classGson序列化接口/抽象类
【发布时间】:2015-02-06 09:14:48
【问题描述】:

如果我使用 接口抽象类 注册 JsonSerializer,例如:

GsonBuilder builder = new GsonBuilder()
    .registerTypeAdapter(MyInterface.class, new MySerializer());
Gson gson = builder.create();

MyInterface i = new MyConcreteClass();
String json = gson.toJson(i); // <--- Serializer is not invoked

序列化程序根本没有在gson.toJson() 中调用。

但是,如果我有一个包含 MyInterface 的类:

public class MyAnotherClass {
    MyInterface i;
    // ...
}

MyAnotherClass c = new MyAnotherClass()
String json = gson.toJson(c); // <--- Serializer is invoked

序列化器被调用。

对我来说,这是一种不一致的行为。它作用于成员变量的方式是寻找 declared 类型而不是 actual 类型,但它作用于“根”对象的方式是不同的。

这是错误/缺陷还是预期行为?如果这是意料之中的,背后有什么原因吗?

【问题讨论】:

    标签: java gson serialization


    【解决方案1】:

    这是预期的行为。 Gson 有一个要使用的默认TypeAdapterFactory 对象列表。您可以在source of the Gson class 中看到它们。

    StringNumberMapCollection...这个通过反射检索要序列化的对象的所有字段,并搜索适当的适配器来序列化字段的值。

    所以当 Gson 必须序列化一个对象时,首先它会尝试通过使用对象的实际类型来找到一个适配器。如果找到的适配器不是ReflectiveTypeAdapter,它将使用它。否则,它会搜索声明类型的适配器,如果不是ReflectiveTypeAdapter,则使用它。否则,它会在对象上使用ReflectiveTypeAdapter(您可以查看TypeAdapterRuntimeTypeWrapper 类的源代码以了解有关此机制的更多详细信息)。这就是你的属性MyInterface i 的行为。

    当你这样做时:

    MyInterface i = new MyConcreteClass();
    String json = gson.toJson(i);
    

    Gson 尝试为MyConcreteClass 类型查找适配器,它找到了ReflectiveTypeAdapter。所以现在它应该搜索一个声明类型的适配器。但是它无法知道声明类型,因为没有对象引用它,这是根对象。您在代码中知道要使用类型 MyInterface,但 Gson 没有此信息,只有对象实例。你可能认为 Gson 可以看到该对象实现了MyInterface,但这不是它的工作方式(如果对象实现了两个接口怎么办?)

    所以,你有两种方法可以解决你的问题:

    1) 调用Gson.toJson时,可以给根对象的声明类型:Gson#toJson(Object, Type)

    String json = gson.toJson(i, MyInterface.class);
    

    2) 注册适配器时,可以指明该适配器适用于所有子类:GsonBuilder#registerTypeHierarchyTree

    GsonBuilder builder = new GsonBuilder()
        .registerTypeHierarchyAdapter(MyInterface.class, new MySerializer());
    

    希望对你有帮助

    【讨论】:

    • 感谢您的回答。尽管如此,由于Java的限制,我认为这是一个预期的缺陷
    • 当我使用 registerTypeHierarchyAdapter 时,当序列化方法执行 result.add("properties", context.serialize(src, src.getClass())) 时,我陷入了一个连续循环中
    • 我尝试了你的第一个解决方案,它给了我空的 json {}
    猜你喜欢
    • 2011-04-07
    • 1970-01-01
    • 2016-01-16
    • 1970-01-01
    • 1970-01-01
    • 2019-06-10
    • 2015-04-07
    • 1970-01-01
    相关资源
    最近更新 更多