[英]Gson serialize interface / abstract class
如果我使用接口或抽象類注冊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
調用序列化程序。
對我來說,這是一種不一致的行為。 它對成員變量的工作方式是查找聲明的類型而不是實際的類型,但它對“根”對象的工作方式是不同的。
這是一個錯誤/缺陷還是預期的行為? 如果這是預期的,背后的任何原因?
這是預期的行為。 Gson有一個默認的TypeAdapterFactory
對象列表供使用。 您可以在Gson類的源代碼中看到它們。
有適用於String
, Number
, Map
, Collection
適配器......最后一個很重要,在沒有適配器可以處理類型時使用:它是ReflectiveTypeAdapter
。 這個通過反射檢索要序列化的對象的所有字段,並搜索適當的適配器以序列化字段的值。
因此,當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());
希望能幫助到你
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.