[英]Deserializing an abstract class in Gson
我有一個 JSON 格式的樹 object 我正在嘗試用 Gson 反序列化。每個節點都包含其子節點作為 object 類型節點的字段。 Node是一個接口,它有幾個具體的class實現。 在反序列化過程中,如果我先驗不知道該節點屬於哪種類型,我如何在反序列化節點時與 Gson 通信具體實現哪個 class ? 每個節點都有一個指定類型的成員字段。 當 object 為序列化形式時,有沒有辦法訪問該字段,並以某種方式將類型傳遞給 Gson?
謝謝!
我建議為Node
添加一個自定義的JsonDeserializer :
Gson gson = new GsonBuilder()
.registerTypeAdapter(Node.class, new NodeDeserializer())
.create();
您將能夠訪問表示反序列化器方法中的節點的JsonElement
,將其轉換為JsonObject
,並檢索指定類型的字段。 然后,您可以基於此創建正確類型的Node
的實例。
您需要注冊JSONSerializer和JSONDeserializer。 您還可以通過以下方式為所有接口實現通用適配器:
這是我自己使用的實現,並且工作正常。
public class PropertyBasedInterfaceMarshal implements
JsonSerializer<Object>, JsonDeserializer<Object> {
private static final String CLASS_META_KEY = "CLASS_META_KEY";
@Override
public Object deserialize(JsonElement jsonElement, Type type,
JsonDeserializationContext jsonDeserializationContext)
throws JsonParseException {
JsonObject jsonObj = jsonElement.getAsJsonObject();
String className = jsonObj.get(CLASS_META_KEY).getAsString();
try {
Class<?> clz = Class.forName(className);
return jsonDeserializationContext.deserialize(jsonElement, clz);
} catch (ClassNotFoundException e) {
throw new JsonParseException(e);
}
}
@Override
public JsonElement serialize(Object object, Type type,
JsonSerializationContext jsonSerializationContext) {
JsonElement jsonEle = jsonSerializationContext.serialize(object, object.getClass());
jsonEle.getAsJsonObject().addProperty(CLASS_META_KEY,
object.getClass().getCanonicalName());
return jsonEle;
}
}
然后,您可以為所有接口注冊此適配器,如下所示
Gson gson = new GsonBuilder()
.registerTypeAdapter(IInterfaceOne.class,
new PropertyBasedInterfaceMarshal())
.registerTypeAdapter(IInterfaceTwo.class,
new PropertyBasedInterfaceMarshal()).create();
我想稍微糾正一下上面的內容
public class PropertyMarshallerAbstractTask implements JsonSerializer<Object>, JsonDeserializer<Object> {
private static final String CLASS_TYPE = "CLASS_TYPE";
@Override
public Object deserialize(JsonElement jsonElement, Type type, JsonDeserializationContext jsonDeserializationContext) throws JsonParseException {
JsonObject jsonObj = jsonElement.getAsJsonObject();
String className = jsonObj.get(CLASS_TYPE).getAsString();
try {
Class<?> clz = Class.forName(className);
return jsonDeserializationContext.deserialize(jsonElement, clz);
} catch (ClassNotFoundException e) {
throw new JsonParseException(e);
}
}
@Override
public JsonElement serialize(Object object, Type type, JsonSerializationContext jsonSerializationContext) {
Gson gson = new Gson(); //without this line it will not work
gson.toJson(object, object.getClass()); //and this one
JsonElement jsonElement = gson.toJsonTree(object); //it needs to replace to another method...toJsonTree
jsonElement.getAsJsonObject().addProperty(CLASS_TYPE, object.getClass().getCanonicalName());
return jsonElement;
}
}
然后我使用它:
Gson gson = new GsonBuilder()
.registerTypeAdapter(AbstractTask.class, new PropertyMarshallerOfAbstractTask())
.create();
然后我可以將 List(我保留一些非抽象類,它們繼承自 Abstract Task)解析為 Json;
它在相反的方向起作用
List<AbstractTask> abstractTasks = gson.fromJson(json, new TypeToken<List<AbstractTask>>(){}.getType());
據我所知,這對非集合類型不起作用,或者更具體地說,對於使用具體類型進行序列化的情況,並且接口類型用於反序列化。 也就是說,如果你有一個實現接口的簡單類並且序列化具體類,那么指定要反序列化的接口,你將最終處於不可恢復的狀態。
在上面的示例中,類型適配器是針對接口注冊的,但是當您使用具體類進行序列化時,它將不會被使用,這意味着將永遠不會設置CLASS_META_KEY數據。
如果您將適配器指定為分層適配器(從而告訴gson將其用於層次結構中的所有類型),您將最終處於無限循環中,因為序列化程序將繼續調用自身。
任何人都知道如何從接口的具體實現序列化,然后只使用接口和InstanceCreator反序列化?
默認情況下,gson似乎會創建具體實例,但不會設置它的字段。
問題記錄在這里:
http://code.google.com/p/google-gson/issues/detail?id=411&q=interface
您必須使用Google Gson中的TypeToken
類。 你當然需要一個通用的類T來使它工作
Type fooType = new TypeToken<Foo<Bar>>() {}.getType();
gson.toJson(foo,fooType);
gson.fromJson(json, fooType);
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.