[英]Deserialize recursive polymorphic class in GSON
class Complex implements Recursive {
Map<String, Recursive> map;
...
}
class Simple implements Recursive { ... }
我如何反序列化此json:
{
"type" : "complex",
"map" : {
"a" : {
"type" : "simple"
},
"b" : {
"type" : "complex",
"map" : {
"ba" : {
"type" : "simple"
}
}
}
}
使用Google GSON?
要反序列化JSON,您需要為遞歸接口使用自定義反序列化器。 在這種類中,您需要檢查JSON並確定要實例化為JSON本身的type字段的類。 在這里,您有一個我為您編寫的示例基本解串器。
當然,管理邊界事件可以得到改善(例如,如果您沒有類型字段,會發生什么情況?)。
package stackoverflow.questions;
import java.lang.reflect.Type;
import java.util.*;
import stackoverflow.questions.Q20254329.*;
import com.google.gson.*;
import com.google.gson.reflect.TypeToken;
public class Q20327670 {
static class Complex implements Recursive {
Map<String, Recursive> map;
@Override
public String toString() {
return "Complex [map=" + map + "]";
}
}
static class Simple implements Recursive {
@Override
public String toString() {
return "Simple []";
}
}
public static class RecursiveDeserializer implements JsonDeserializer<Recursive> {
public Recursive deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException {
Recursive r = null;
if (json == null)
r = null;
else {
JsonElement t = json.getAsJsonObject().get("type");
String type = null;
if (t != null) {
type = t.getAsString();
switch (type) {
case "complex": {
Complex c = new Complex();
JsonElement e = json.getAsJsonObject().get("map");
if (e != null) {
Type mapType = new TypeToken<Map<String, Recursive>>() {}.getType();
c.map = context.deserialize(e, mapType);
}
r = c;
break;
}
case "simple": {
r = new Simple();
break;
}
// remember to manage default..
}
}
}
return r;
}
}
public static void main(String[] args) {
String json = " { " +
" \"type\" : \"complex\", " +
" \"map\" : { " +
" \"a\" : { " +
" \"type\" : \"simple\" " +
" }, " +
" \"b\" : { " +
" \"type\" : \"complex\", " +
" \"map\" : { " +
" \"ba\" : { " +
" \"type\" : \"simple\" " +
" } " +
" } " +
" } " +
" } } ";
GsonBuilder gb = new GsonBuilder();
gb.registerTypeAdapter(Recursive.class, new RecursiveDeserializer());
Gson gson = gb.create();
Recursive r = gson.fromJson(json, Recursive.class);
System.out.println(r);
}
}
這是我的代碼的結果:
Complex [map={a=Simple [], b=Complex [map={ba=Simple []}]}]
抱歉回復太晚(因為此問題已得到回答)。 但是我想我可以給這個問題2美分。
正如@Parobay所說的那樣,您可以添加一個特殊的{"type": "complex"}
參數以了解要反序列化的類。 但是如前所述,您必須將所有數據移動到一個{"instance": {}}
子對象,該子對象感覺很笨拙,因為您必須手動控制在big switch
創建的實例。
您可以改用TypeFactory
類來更好地處理這種情況。 更確切地說,有一個特殊的工廠(該工廠目前未與Gson捆綁在一起,應該將其命名為RuntimeTypeAdapterFactory
。 復制有關該類的文檔說明:
適應其運行時類型可能不同於其聲明類型的值。 當字段的類型與GSON反序列化該字段時應創建的類型不同時,這是必需的。 例如,考慮以下類型:
{\n 抽象類Shape {\n int x;\n 詮釋\n }\n 類Circle擴展Shape {\n 整數半徑\n }\n 矩形擴展Shape的類{\n 整數寬度\n 整數高度\n }\n 鑽石級延伸形狀{\n 整數寬度\n 整數高度\n }\n 類圖{\n 形狀bottomShape;\n 形狀topShape;\n }}如果沒有其他類型信息,則序列化的JSON不明確。 該圖中的底部形狀是矩形還是菱形?
{\n {\n “ bottomShape”:{\n “寬度”:10,\n “身高”:5\n “ x”:0,\n “ y”:0\n },\n “ topShape”:{\n “半徑”:2\n “ x”:4\n “ y”:1\n }\n }}此類通過將類型信息添加到序列化的JSON並在反序列化JSON時保留該類型信息來解決此問題:{\n {\n “ bottomShape”:{\n “ type”:“ Diamond”,\n “寬度”:10,\n “身高”:5\n “ x”:0,\n “ y”:0\n },\n “ topShape”:{\n “ type”:“ Circle”,\n “半徑”:2\n “ x”:4\n “ y”:1\n }\n }}類型字段名稱({@code“ type”})和類型標簽({@code“ Rectangle”})都是可配置的。
因此,您只需要使用以下命令創建Gson對象:
RuntimeTypeAdapter<Shape> shapeAdapter
= RuntimeTypeAdapter.of(Shape.class, "type")
.registerSubtype(Rectangle.class, "Rectangle");
Gson gson = new GsonBuilder()
.registerTypeAdapter(Shape.class, shapeAdapter)
.create();
而且,您可以自動(反)序列化對象。 我創建了這個Factory的變體,而不是期望type
參數,而是嘗試通過運行自定義正則表達式來發現什么樣的對象(這樣可以避免創建額外的參數,或者當您沒有完全控制權時API)。
在這里,我為您提供了兩個帶有來源的鏈接:
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.