当前位置: 首页 > 面试题库 >

Gson序列化多态对象列表

贺栋
2023-03-14
问题内容

我正在尝试使用Gson将涉及多态的对象序列化/反序列化为JSON。

这是我的序列化代码:

ObixBaseObj lobbyObj = new ObixBaseObj();
lobbyObj.setIs("obix:Lobby");

ObixOp batchOp = new ObixOp();
batchOp.setName("batch");
batchOp.setIn("obix:BatchIn");
batchOp.setOut("obix:BatchOut");

lobbyObj.addChild(batchOp);

Gson gson = new Gson();
System.out.println(gson.toJson(lobbyObj));

结果如下:

 {"obix":"obj","is":"obix:Lobby","children":[{"obix":"op","name":"batch"}]}

序列化大多的作品,除了它缺少继承成员的内容(尤其是obix:BatchInobixBatchout字符串丢失)。这是我的基类:

public class ObixBaseObj  {
    protected String obix;
    private String display;
    private String displayName;
    private ArrayList<ObixBaseObj> children;

    public ObixBaseObj()
    {
        obix = "obj";
    }

    public void setName(String name) {
        this.name = name;
    }
        ...
}

这是我的继承类(ObixOp)的样子:

public class ObixOp extends ObixBaseObj {
    private String in;
    private String out;

    public ObixOp() {
        obix = "op";
    }
    public ObixOp(String in, String out) {
        obix = "op";
        this.in = in;
        this.out = out;
    }
    public String getIn() {
        return in;
    }
    public void setIn(String in) {
        this.in = in;
    }
    public String getOut() {
        return out;
    }
    public void setOut(String out) {
        this.out = out;
    }
}

我意识到我可以为此使用适配器,但是问题是我正在序列化基类type的集合ObixBaseObj。从中继承大约25个类。我该如何优雅地进行这项工作?


问题答案:

我认为自定义序列化器/反序列化器是继续进行的唯一方法,我尝试向您建议实现我发现的最紧凑的方法。对于没有使用您的类,我深表歉意,但是想法是一样的(我只想要至少1个基类和2个扩展类)。

BaseClass.java

public class BaseClass{

    @Override
    public String toString() {
        return "BaseClass [list=" + list + ", isA=" + isA + ", x=" + x + "]";
    }

    public ArrayList<BaseClass> list = new ArrayList<BaseClass>();

    protected String isA="BaseClass"; 
    public int x;

 }

ExtendedClass1.java

public class ExtendedClass1 extends BaseClass{

    @Override
    public String toString() {
       return "ExtendedClass1 [total=" + total + ", number=" + number
            + ", list=" + list + ", isA=" + isA + ", x=" + x + "]";
    }

    public ExtendedClass1(){
        isA = "ExtendedClass1";
    }

    public Long total;
    public Long number;

}

ExtendedClass2.java

public class ExtendedClass2 extends BaseClass{

    @Override
    public String toString() {
      return "ExtendedClass2 [total=" + total + ", list=" + list + ", isA="
            + isA + ", x=" + x + "]";
    }

    public ExtendedClass2(){
        isA = "ExtendedClass2";
    }

    public Long total;

}

CustomDeserializer.java

public class CustomDeserializer implements JsonDeserializer<List<BaseClass>> {

    private static Map<String, Class> map = new TreeMap<String, Class>();

    static {
        map.put("BaseClass", BaseClass.class);
        map.put("ExtendedClass1", ExtendedClass1.class);
        map.put("ExtendedClass2", ExtendedClass2.class);
    }

    public List<BaseClass> deserialize(JsonElement json, Type typeOfT,
            JsonDeserializationContext context) throws JsonParseException {

        List list = new ArrayList<BaseClass>();
        JsonArray ja = json.getAsJsonArray();

        for (JsonElement je : ja) {

            String type = je.getAsJsonObject().get("isA").getAsString();
            Class c = map.get(type);
            if (c == null)
                throw new RuntimeException("Unknow class: " + type);
            list.add(context.deserialize(je, c));
        }

        return list;

    }

}

CustomSerializer.java

public class CustomSerializer implements JsonSerializer<ArrayList<BaseClass>> {

    private static Map<String, Class> map = new TreeMap<String, Class>();

    static {
        map.put("BaseClass", BaseClass.class);
        map.put("ExtendedClass1", ExtendedClass1.class);
        map.put("ExtendedClass2", ExtendedClass2.class);
    }

    @Override
    public JsonElement serialize(ArrayList<BaseClass> src, Type typeOfSrc,
            JsonSerializationContext context) {
        if (src == null)
            return null;
        else {
            JsonArray ja = new JsonArray();
            for (BaseClass bc : src) {
                Class c = map.get(bc.isA);
                if (c == null)
                    throw new RuntimeException("Unknow class: " + bc.isA);
                ja.add(context.serialize(bc, c));

            }
            return ja;
        }
    }
}

现在,这是我用来测试整个程序的代码:

public static void main(String[] args) {

  BaseClass c1 = new BaseClass();
  ExtendedClass1 e1 = new ExtendedClass1();
  e1.total = 100L;
  e1.number = 5L;
  ExtendedClass2 e2 = new ExtendedClass2();
  e2.total = 200L;
  e2.x = 5;
  BaseClass c2 = new BaseClass();

  c1.list.add(e1);
  c1.list.add(e2);
  c1.list.add(c2);


  List<BaseClass> al = new ArrayList<BaseClass>();

  // this is the instance of BaseClass before serialization
  System.out.println(c1);

  GsonBuilder gb = new GsonBuilder();

  gb.registerTypeAdapter(al.getClass(), new CustomDeserializer());
  gb.registerTypeAdapter(al.getClass(), new CustomSerializer());
  Gson gson = gb.create();

  String json = gson.toJson(c1);
  // this is the corresponding json
  System.out.println(json);

  BaseClass newC1 = gson.fromJson(json, BaseClass.class);

  System.out.println(newC1);

}

这是我的处决:

BaseClass [list=[ExtendedClass1 [total=100, number=5, list=[], isA=ExtendedClass1, x=0], ExtendedClass2 [total=200, list=[], isA=ExtendedClass2, x=5], BaseClass [list=[], isA=BaseClass, x=0]], isA=BaseClass, x=0]
{"list":[{"total":100,"number":5,"list":[],"isA":"ExtendedClass1","x":0},{"total":200,"list":[],"isA":"ExtendedClass2","x":5},{"list":[],"isA":"BaseClass","x":0}],"isA":"BaseClass","x":0}
BaseClass [list=[ExtendedClass1 [total=100, number=5, list=[], isA=ExtendedClass1, x=0], ExtendedClass2 [total=200, list=[], isA=ExtendedClass2, x=5], BaseClass [list=[], isA=BaseClass, x=0]], isA=BaseClass, x=0]

一些解释:该技巧由串行器/解串器中的另一个Gson完成。我只使用isA字段来发现合适的班级。为了更快,我使用地图将isA字符串关联到相应的类。然后,我使用第二个Gson对象进行适当的序列化/反序列化。我将其声明为静态,因此您不会因多次分配Gson而减慢序列化/反序列化。

Pro 实际上,您编写的代码并不比这更多,而是让Gson完成所有工作。您只需要记住在地图中放置一个新的子类(例外使您想起了这一点)。

缺点 您有两张地图。我认为我的实现可以做些改进以避免映射重复,但是我将它们留给您(或将来的编辑器,如果有的话)。

也许您想将序列化和反序列化统一为一个唯一的对象,应该检查TypeAdapter类或尝试使用同时实现两个接口的对象。



 类似资料:
  • 我正在尝试使用Gson将一个涉及多态性的对象序列化/反序列化为JSON。 这是我的序列化代码: 结果是这样的: 序列化主要工作,除了它缺少继承成员的内容(特别是和字符串丢失)。这是我的基类: 下面是我继承的类(ObixOp)的样子: 我意识到我可以使用适配器来实现这一点,但问题是我正在序列化一个基类类型的集合。大约有25个类继承自此。我怎样才能优雅地完成这项工作?

  • 问题内容: 使用Gson 2.2.2,我正在尝试序列化POJO(行为)的数组列表。 我有一个适配器,几乎是我在网上看到的一个副本: 我这样注册: 然后,当我尝试序列化我的ArrayList时: 我出现堆栈溢出。 似乎在线上: 它开始递归循环,一次又一次地通过我的序列化器。那么,我该如何注册它以免发生这种情况?我需要序列化列表并保持多态性。 问题答案: 看起来您发现了JsonSerializer文档

  • 主要内容:示例我们将一个Java对象序列化为一个Json文件,然后读取该Json文件以获取对象。 在这个例子中,创建一个类。 然后将对象列化后存储在文件中,该文件将具有对象的json表示形式。 示例 在中创建一个名为的Java类文件,参考以下代码 - 执行上面示例代码,得到以下结果 -

  • 我有一个接口,其中和实现。服务器会返回这样的响应- 相应的类来建模它是 中的声明它是哪种车辆。我需要反序列化的成一个对象取决于。如果是,我需要在反序列化和期间使用反序列化。 如何使用gson实现这一点? 编辑-这篇文章的不同之处在于类类型()包含在需要反序列化的中。这里不是。如果在内,我可以为编写自定义反序列化程序,检查,并进行相应的反序列化。但是我想我需要为编写一个自定义反序列化程序,在这里我创

  • 我想将这个对象序列化为JSON字符串 并得到如下结果: 我试着用 但不是这样,我得到了: 个性化序列化: 欢迎提出任何建议 谢谢,马里奥

  • 这里有人知道如何使用TypeAdapterFactory基于“type”字段进行反序列化而不需要将整个json流读取到JsonElement对象树中吗?