Vic*_*ong 3 java serializer gson
如果我注册一个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
Run Code Online (Sandbox Code Playgroud)
不会调用序列化程序gson.toJson().
但是,如果我有一个包含MyInterface以下内容的类:
public class MyAnotherClass {
MyInterface i;
// ...
}
MyAnotherClass c = new MyAnotherClass()
String json = gson.toJson(c); // <--- Serializer is invoked
Run Code Online (Sandbox Code Playgroud)
调用序列化程序.
对我来说,这是一种不一致的行为.它对成员变量的工作方式是查找声明的类型而不是实际的类型,但它对"根"对象的工作方式是不同的.
这是一个错误/缺陷还是预期的行为?如果这是预期的,背后的任何原因?
小智 11
这是预期的行为.Gson有一个TypeAdapterFactory要使用的默认对象列表.您可以在Gson类的源代码中看到它们.
还有用于适配器String,Number,Map,Collection...最后一个是重要的,使用时无适配器可以处理一个类型:它是ReflectiveTypeAdapter.这个通过反射检索要序列化的对象的所有字段,并搜索适当的适配器以序列化字段的值.
因此,当Gson必须序列化对象时,首先它会尝试使用对象的实际类型来查找适配器.如果找到的适配器不是ReflectiveTypeAdapter,则使用它.否则,它会搜索具有声明类型的适配器,如果它不是,则使用它ReflectiveTypeAdapter.否则它使用ReflectiveTypeAdapteron对象(您可以查看类TypeAdapterRuntimeTypeWrapper的源代码以获得有关此mecanism的更多详细信息).这就是你对属性的行为MyInterface i.
当你这样做时:
MyInterface i = new MyConcreteClass();
String json = gson.toJson(i);
Run Code Online (Sandbox Code Playgroud)
Gson试图找到该类型的适配器MyConcreteClass,它找到了ReflectiveTypeAdapter.所以现在它应该搜索具有声明类型的适配器.但它无法知道声明类型,因为没有对象引用它,这是根对象.您在代码中知道要使用该类型MyInterface,但Gson没有此信息且只有对象实例.您可能认为Gson可以看到该对象实现了MyInterface,但这不是它的工作方式(以及如果该对象实现两个接口该怎么办?)
那么,您有两种方法可以解决您的问题:
1)当你调用时Gson.toJson,你可以给出根对象的声明类型:Gson#toJson(Object,Type)
String json = gson.toJson(i, MyInterface.class);
Run Code Online (Sandbox Code Playgroud)
2)注册适配器时,可以指示此适配器适用于所有子类:GsonBuilder #registerTypeHierarchyTree
GsonBuilder builder = new GsonBuilder()
.registerTypeHierarchyAdapter(MyInterface.class, new MySerializer());
Run Code Online (Sandbox Code Playgroud)
希望能帮助到你