如果我用一个接口或抽象类注册一个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
调用序列化程序。
对我来说,这是一种不一致的行为。它对成员变量的工作方式是寻找 * 声明的 * 类型而不是 * 实际的 * 类型,但它对“根”对象的工作方式是不同的。
这是Bug /缺陷还是预期行为?如果是预期行为,有什么原因吗?
1条答案
按热度按时间b4qexyjb1#
这是预期的行为。Gson有一个默认
TypeAdapterFactory
对象的列表可以使用。你可以在Gson类的源代码中看到它们。有
String
、Number
、Map
、Collection
等适配器。最后一个适配器很重要,在没有适配器可以处理类型时使用:它是ReflectiveTypeAdapter
,通过反射检索要序列化的对象的所有字段,并搜索适当的适配器来序列化字段的值。所以当Gson需要序列化一个对象时,它首先会尝试使用对象的实际类型来找到适配器,如果找到的适配器不是
ReflectiveTypeAdapter
,它使用它。否则,它搜索具有声明类型的适配器,如果不是ReflectiveTypeAdapter
,则使用它。否则,它使用对象上的ReflectiveTypeAdapter
(你可以查看类TypeAdapterRuntimeTypeWrapper的源代码,以获得关于此机制的更多详细信息)。这是你的属性MyInterface i
的行为。当您执行以下操作时:
Gson尝试寻找
MyConcreteClass
类型的适配器,它找到了ReflectiveTypeAdapter
。所以现在它应该搜索声明类型的适配器。但是它无法知道声明类型,因为没有对象引用它,这是根对象。在代码中,你知道你想使用MyInterface
类型,但Gson没有这些信息,只有对象示例。您可能认为Gson可以看到对象实现了MyInterface
,但这不是它的工作方式(如果对象实现了两个接口,该怎么办?)所以,你有两种方法来解决你的问题:
1)当调用
Gson.toJson
时,可以为根对象给予声明性类型:Gson#toJson(对象,类型)2)注册适配器时,可以指明此适配器适用于所有子类:GsonBuilder#注册表类型层次结构树
希望能有所帮助