在GSON中反序列化递归多态类

class Complex implements Recursive { Map map; ... } class Simple implements Recursive { ... } 

如何反序列化这个json:

 { "type" : "complex", "map" : { "a" : { "type" : "simple" }, "b" : { "type" : "complex", "map" : { "ba" : { "type" : "simple" } } } } 

使用谷歌GSON?

要反序列化您的JSON,您需要为Recursive接口提供自定义反序列化器。 在这种类中,您需要检查您的JSON并确定要实例化为JSON本身中的类型字段的类。 在这里,您有一个我为您编写的基本反序列化示例。

当然,可以改进管理边界情况(例如,如果你没有类型字段会发生什么?)。

 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 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 { 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>() {}.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": {}}子对象,因为您必须手动控制在大型switch创建的实例,因此感觉很麻烦。

您可以使用TypeFactory类来更好地处理这种情况。 更准确地说,有一个名为RuntimeTypeAdapterFactory特殊工厂(目前没有与Gson捆绑在一起)。 复制有关此课程的文档说明:

调整运行时类型可能与其声明类型不同的值。 当字段的类型与GSON在反序列化该字段时应创建的类型不同时,这是必需的。 例如,请考虑以下类型:

  {
    抽象类Shape {
       int x;
       int y;
     }
     class Circle扩展Shape {
       int radius;
     }
     class Rectangle extends Shape {
       int宽度;
       int height;
     }
     class Diamond扩展Shape {
       int宽度;
       int height;
     }
     class Drawing {
      形状底部形状;
      形状topShape;
     }} 

没有其他类型信息,序列化的JSON是不明确的。 此图纸中的底部形状是矩形还是菱形?

  {
     {
       “bottomShape”:{
         “宽度”:10,
         “身高”:5,
         “x”:0,
         “y”:0
       },
       “topShape”:{
         “半径”:2,
         “x”:4,
         “y”:1
       }
     }} 

此类通过向序列化JSON添加类型信息并在反序列化JSON时表彰该类型信息来解决此问题:

  {
     {
       “bottomShape”:{
         “类型”:“钻石”,
         “宽度”:10,
         “身高”:5,
         “x”:0,
         “y”:0
       },
       “topShape”:{
         “type”:“Circle”,
         “半径”:2,
         “x”:4,
         “y”:1
       }
     }} 

类型字段名称({@code“type”})和类型标签({@code“Rectangle”})都是可配置的。

所以你只需要创建你的Gson对象:

 RuntimeTypeAdapter shapeAdapter = RuntimeTypeAdapter.of(Shape.class, "type") .registerSubtype(Rectangle.class, "Rectangle"); Gson gson = new GsonBuilder() .registerTypeAdapter(Shape.class, shapeAdapter) .create(); 

瞧,你有对象的自动(反)序列化。 我创建了这个Factory的变体,而不是期望一个type参数,尝试通过运行自定义正则表达式来发现什么类型的对象(这样你可以避免创建额外的参数,或者当你没有完全控制时的API)。

在这里,我给你两个来源链接:

  • 原始RuntimeTypeAdapterFactory源 。
  • 我修改了RuntimeRegexTypeAdapterFactory源码 。