简体   繁体   中英

Gson Deserializing Problem - If Type parameter is child class could not deserialize

In Master class for the variable Generic<Parent> generic i am passing a Child Object in main() . During serializing i am getting correct output. But while deserializing Child Object is missing. Could anyone give suggesstions.

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;
        }

    }

}

Problem

Gson tries to deserialize the generic value into Parent , not Child . Since there is type as null , you can see no data in the object deserialized which appears as {} . If you add child.setType("type"); then the outputs become:

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

However, the field name is not present in the Parent class but the Child class and Gson simply has no idea what subclass of Parent it is (if so) and completely ignores the value, which is a correct behavior.

Solution

I find basically two choices (I use all-args constructor for sake of brevity):

  1. Elevate the upper-bounded generic type parameter to the Master class and specify the particular Child type at the point of deserialization using com.google.gson.reflect.TypeToken and java.lang.reflect.Type :

     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. Hardcode the particular generic type Generic<Child> inside the Master class. The deserialization gets the way easier, yet the design is less flexible:

     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"}}}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM