Gson Type Adapter vs. Custom Deseralizer

前端 未结 3 1475
面向向阳花
面向向阳花 2020-12-29 06:54

The example below shows a class (Club) that contains a collection of an abstract class (Member). I\'m confused as to whether I need a TypeAdapter or JsonDeserializer to make

3条回答
  •  抹茶落季
    2020-12-29 07:33

    Ok, real working example (I'm pretty sure this time).

    The Club

    package gson.test;
    import java.util.ArrayList;
    import com.google.gson.Gson;
    import com.google.gson.GsonBuilder;
    
    public class Club {
        public static void main(String[] args) {
            // Setup a Club with 2 members
            Club myClub = new Club();
            myClub.addMember(new Silver("Jack"));
            myClub.addMember(new Gold("Jill"));
            myClub.addMember(new Silver("Mike"));
    
            // Get the GSON Object and register Type Adapter
            GsonBuilder builder = new GsonBuilder();
            builder.registerTypeAdapter(Member.class, new MemberDeserializer());
            builder.registerTypeAdapter(Member.class, new MemberSerializer());
            builder.setPrettyPrinting();
            Gson gson = builder.create();
    
            // Serialize Club to JSON
            String myJsonClub = gson.toJson(myClub); 
    
            // De-Serialize to Club
            Club myNewClub = gson.fromJson(myJsonClub, Club.class);
            System.out.println(myClub.equals(myNewClub) ? "Cloned!" : "Failed");
            System.out.println(gson.toJson(myNewClub));
        }
    
        private String title = "MyClub";
        private ArrayList members = new ArrayList();
    
        public boolean equals(Object club) {
            Club that = (Club) club;
            if (!this.title.equals(that.title)) return false;
            for (int i=0; i

    The Member Abstract Class

    package gson.test;
    public abstract class Member {
        private String clsname = this.getClass().getName() ;
        private int type;
        private String name = "unknown";
    
        public Member() { }
        public Member(String theName) {this.name = theName;}
        public int getType() { return type; }
        public void setType(int type) { this.type = type; }
        public boolean equals(Object member) {
            Member that = (Member) member;
            return this.name.equals(that.name);
        }
    }
    

    The Concrete Sub-Classes Silver and Gold

    package gson.test;
    public class Silver extends Member {
        private String silverData = "SomeSilverData";
        public Silver() { 
            super(); 
            this.setType(1); 
        }
        public Silver(String theName) {
            super(theName); 
            this.setType(1); 
        }
        public boolean equals(Object that) {
            Silver silver = (Silver)that;
            return (super.equals(that) && this.silverData.equals(silver.silverData)); 
        }
    }
    
    package gson.test;
    public class Gold extends Member {
        private String goldData = "SomeGoldData";
        private String extraData = "Extra Gold Data";
        public Gold() {
            super(); 
            this.setType(2);
        }
        public Gold(String theName) { 
            super(theName); 
            this.setType(2); 
        }
        public boolean equals(Gold that) {
            Gold gold = (Gold) that;
            return (super.equals(that) && this.goldData.equals(gold.goldData)); 
        }
    }
    

    The Custom Member Serailizer

    package gson.test;
    import java.lang.reflect.Type;
    import com.google.gson.JsonElement;
    import com.google.gson.JsonSerializationContext;
    import com.google.gson.JsonSerializer;
    
    public class MemberSerializer implements JsonSerializer {
    
        public JsonElement serialize(Member src, Type member, JsonSerializationContext context) {
            switch (src.getType()) {
                case 1: return context.serialize((Silver)src);
                case 2: return context.serialize((Gold)src);
                default: return null;
            }
        }
    }
    

    The custom Deserializer

    package gson.test;
    import java.lang.reflect.Type;
    import com.google.gson.JsonDeserializationContext;
    import com.google.gson.JsonDeserializer;
    import com.google.gson.JsonElement;
    
    public class MemberDeserializer implements JsonDeserializer {
        @Override
        public Member deserialize(JsonElement json, Type member, JsonDeserializationContext context) {
            int myType = json.getAsJsonObject().get("type").getAsInt();
            switch (myType) {
                case 1: return context.deserialize(json, Silver.class);
                case 2: return context.deserialize(json, Gold.class);
                default: return null;
            }
        }
    }
    

    And... the output

    Cloned!
    {
      "title": "MyClub",
      "members": [
        {
          "silverData": "SomeSilverData",
          "clsname": "gson.test.Silver",
          "type": 1,
          "name": "Jack"
        },
        {
          "goldData": "SomeGoldData",
          "extraData": "Extra Gold Data",
          "clsname": "gson.test.Gold",
          "type": 2,
          "name": "Jill"
        },
        {
          "silverData": "SomeSilverData",
          "clsname": "gson.test.Silver",
          "type": 1,
          "name": "Mike"
        }
      ]
    }
    

    I should note that my real use-case is one where performance should not be an issue, I'm loading a cache of objects from jSon text files so the frequency with this code is executed makes performance much less important than maintainability.

提交回复
热议问题