Gson - deserialization to specific object type based on field value

后端 未结 4 663
隐瞒了意图╮
隐瞒了意图╮ 2020-12-01 06:33

I want to deserialize json objects to specific types of objects (using Gson library) based on type field value, eg.:

[
    {
          \"type\":         


        
相关标签:
4条回答
  • 2020-12-01 07:06

    @stephane-k 's answer works, but it is a bit confusing and could be improved upon (see comments to his answer)

    Copy https://github.com/google/gson/blob/master/extras/src/main/java/com/google/gson/typeadapters/RuntimeTypeAdapterFactory.java into your project. (It's ok; these classes are designed to be copy/pasted https://github.com/google/gson/issues/845#issuecomment-217231315)

    Setup model inheritance:

    // abstract is optional
    abstract class BaseClass {
    }
    
    class Type1Model extends BaseClass {
    }
    
    class Type2Model extends BaseClass {
    }
    

    Setup GSON or update existing GSON:

    RuntimeTypeAdapterFactory<BaseClass> typeAdapterFactory = RuntimeTypeAdapterFactory
            .of(BaseClass.class, "type")
            .registerSubtype(Type1Model.class, "type1")
            .registerSubtype(Type2Model.class, "type2");
    
    Gson gson = new GsonBuilder().registerTypeAdapterFactory(typeAdapterFactory)
                    .create();
    

    Deserialize your JSON into base class:

    String jsonString = ...
    BaseClass baseInstance = gson.fromJson(jsonString, BaseClass.class);
    

    baseInstance will be instanceof either Type1Model or Type2Model.

    From here you can either code to an interface or check instanceof and cast.

    0 讨论(0)
  • 2020-12-01 07:16

    If you have a lot of sub types and you do not want to or cannot maintain a list of them, you can also use an annotation based approach.

    Here is the required code and also some usage examples: https://gist.github.com/LostMekka/d90ade1fe051732d6b4ac60deea4f9c2 (it is Kotlin, but can easily be ported to Java)

    For me, this approach is especially appealing, since I write a small library that does not know all possible sub types at compile time.

    0 讨论(0)
  • 2020-12-01 07:20

    You may implement a JsonDeserializer and use it while parsing your Json value to a Java instance. I'll try to show it with a code which is going to give you the idea:

    1) Define your custom JsonDeserializer class which creates different instance of classes by incoming json value's id property:

    class MyTypeModelDeserializer implements JsonDeserializer<MyBaseTypeModel> {
    
        @Override
        public MyBaseTypeModel deserialize(final JsonElement json, final Type typeOfT, final JsonDeserializationContext context)
                throws JsonParseException {
    
            JsonObject jsonObject = json.getAsJsonObject();
    
            JsonElement jsonType = jsonObject.get("type");
            String type = jsonType.getAsString();
    
            MyBaseTypeModel typeModel = null;     
    
            if("type1".equals(type)) {
                typeModel = new Type1Model();
            } else if("type2".equals(type)) {
                typeModel = new Type2Model();
            }
            // TODO : set properties of type model
    
            return typeModel;
        }
    }
    

    2) Define a base class for your different instance of java objects:

    class  MyBaseTypeModel {
        private String type;
        // TODO : add other shared fields here
    }
    

    3) Define your different instance of java objects' classes which extend your base class:

    class Type1Model extends MyBaseTypeModel {
        // TODO: add specific fields for this class
    }
    
    class Type2Model extends MyBaseTypeModel {
        // TODO: add specific fields for this class
    }
    

    4) Use these classes while parsing your json value to a bean:

    GsonBuilder gsonBuilder = new GsonBuilder();
    gsonBuilder.registerTypeAdapter(MyBaseTypeModel.class, new MyTypeModelDeserializer());
    Gson gson = gsonBuilder.create();
    
    MyBaseTypeModel myTypeModel = gson.fromJson(myJsonString, MyBaseTypeModel.class);
    

    I can not test it right now but I hope you get the idea. Also this link would be very helpful.

    0 讨论(0)
  • 2020-12-01 07:20

    use https://github.com/google/gson/blob/master/extras/src/main/java/com/google/gson/typeadapters/RuntimeTypeAdapterFactory.java

    then configure it with

    public static final class JsonAdapterFactory extends 
        RuntimeTypeAdapterFactory<MediumSummaryInfo> {
            public JsonAdapterFactory() {
                super(MyBaseType.class, "type");
                registerSubtype(MySubtype1.class, "type1");
                registerSubtype(MySubtype2.class, "type2");
            }
    }
    

    and add the annotation:

    @JsonAdapter(MyBaseType.JsonAdapterFactory.class)

    to MyBaseType

    Much better.

    0 讨论(0)
提交回复
热议问题