【问题标题】:Gson Deserializing Problem - If Type parameter is child class could not deserializeGson 反序列化问题 - 如果类型参数是子类无法反序列化
【发布时间】:2020-10-20 07:31:36
【问题描述】:

在变量Generic<Parent> genericMaster 类中,我在main() 中传递了一个子对象。在序列化期间,我得到了正确的输出。但是在反序列化子对象时丢失了。谁能给点建议。

public class GenericSample {
    public static void main(String[] args) {
        Generic<Parent> generic = new Generic<Parent>();
        Child child = new Child();
        child.setName("I am child");
        generic.setT(child);

        Gson gson = new Gson();

        Master master = new Master();
        master.setId(2);
        master.setGeneric(generic);

        String valMaster = gson.toJson(master);
        System.out.println(valMaster);
        /*
         * Output: {"id":2,"generic":{"t":{"name":"I am child"}}}
         */

        Master master2 = gson.fromJson(valMaster, Master.class);
        String valMaster2 = gson.toJson(master2);
        System.out.println(valMaster2);
        /*
         * Child Object is missing
         * Output: {"id":2,"generic":{"t":{}}}
         */
    }

    static class Master {
        private int id;
        private Generic<Parent> generic;

        public int getId() {
            return id;
        }

        public void setId(int id) {
            this.id = id;
        }

        public Generic<Parent> getGeneric() {
            return generic;
        }

        public void setGeneric(Generic<Parent> generic) {
            this.generic = generic;
        }

    }

    static class Generic<T> {
        T t;

        public T getT() {
            return t;
        }

        public void setT(T t) {
            this.t = t;
        }
        
    }
    static class Parent {
        private String type;

        public String getType() {
            return type;
        }

        public void setType(String type) {
            this.type = type;
        }

    }

    static class Child extends Parent {
        private String name;

        public String getName() {
            return name;
        }

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

    }

}

【问题讨论】:

    标签: java generics gson json-deserialization


    【解决方案1】:

    问题

    Gson 尝试将通用值反序列化为 Parent,而不是 Child。由于typenull 一样存在,因此您在反序列化的对象中看不到任何数据,它显示为{}。如果添加child.setType("type");,则输出变为:

    • valMaster1: {"id":2,"generic":{"t":{"name":"I am child","type":"type"}}}
    • valMaster2: {"id":2,"generic":{"t":{"type":"type"}}}

    但是,name 字段 出现在 Parent 类中,但 Child 类和 Gson 根本不知道它是 Parent 的哪个子类(如果是的话)并完全忽略该值,这是正确的行为。

    解决方案

    我发现基本上有两种选择(为简洁起见,我使用全参数构造函数):

    1. 将上限泛型类型参数提升为Master 类,并在反序列化点使用com.google.gson.reflect.TypeTokenjava.lang.reflect.Type 指定特定的Child 类型:

      static class Master<T extends Parent> {
          private int id;
          private Generic<T> generic;
      
          /* getters, setters and all-args constructor */
      }
      
      Child child = new Child("I am child");
      Generic<Parent> generic = new Generic<>(child);
      Master<Parent> master = new Master<>(2, generic);
      
      Gson gson = new Gson();
      String valMaster = gson.toJson(master);
      System.out.println(valMaster);                           
      // {"id":2,"generic":{"t":{"name":"I am child"}}}
      
      Type type = new TypeToken<Master<Child>>() {}.getType();
      Master<Child> master2 = gson.fromJson(valMaster, type);
      String valMaster2 = gson.toJson(master2);
      System.out.println(valMaster2);
      // {"id":2,"generic":{"t":{"name":"I am child"}}}
      
      
    2. Master 类中硬编码特定的泛型类型Generic&lt;Child&gt;。反序列化变得更容易,但设计不太灵活:

      static class Master {
          private int id;
          private Generic<Child> generic;
      
          /* getters, setters and all-args constructor */
      }
      
      Child child = new Child("I am child");
      Generic<Child> generic = new Generic<>(child);
      Master master = new Master(2, generic);
      
      Gson gson = new Gson();
      String valMaster = gson.toJson(master);
      System.out.println(valMaster);
      // {"id":2,"generic":{"t":{"name":"I am child"}}}
      
      Master master2 = gson.fromJson(valMaster, Master.class);
      String valMaster2 = gson.toJson(master2);
      System.out.println(valMaster2);
      // {"id":2,"generic":{"t":{"name":"I am child"}}}
      

    【讨论】:

    • 我确实相信 OP 要求的是完美的往返序列化/反序列化,而不是临时硬编码子类。
    • @fluffy:你读过第一对sn-ps吗?它没有说明硬编码
    • 是的,我做到了。您的解决方案编号中有Type type = new TypeToken&lt;Master&lt;Child&gt;&gt;() {}.getType();。 1.
    • 请在pastebin.com/fXL4r1s9找到往返解决方案
    • 我觉得不错。但是,您必须删除从 Parent 声明的字段 type。谢谢。我学到了一些新东西。随意添加答案。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-07-16
    • 1970-01-01
    相关资源
    最近更新 更多