簡體   English   中英

Gson序列化接口/抽象類

[英]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類源代碼中看到它們。

有適用於StringNumberMapCollection適配器......最后一個很重要,在沒有適配器可以處理類型時使用:它是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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM