Gson - deserialization to specific object type based on field value

gson deserialize nested objects
gson custom deserializer for field
gson deserialize map
gson deserialize field name
gson deserialize null
gson ignore unknown fields
gson deserialize array
kotlin gson custom deserializer

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

[
    {
          "type": "type1",
          "id": "131481204101",
          "url": "http://something.com",
          "name": "BLAH BLAH",
          "icon": "SOME_STRING",
          "price": "FREE",
          "backgroundUrl": "SOME_STRING"
    },
    {
        ....
    }
]

So type field will have different (but known) values. Based on that value I need to deserialize that json object to appropriate model object, eg.: Type1Model, Type2Model etc. I know I can easily do that before deserialization by converting it to JSONArray, iterate through it and resolve which type it should be deserialized to. But I think it's ugly approach and I'm looking for better way. Any suggestions?

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.

Retrofit an GSON: deserialize a specific object type based on the , Hi, I'm trying to deserialize a specific object type based on the value of a field. this is my json: { "orderId": 123121, "note": "notas raul", "percent":  Deserialize JSON With Non-Matching Field Names to Object Now, let's see how Gson does with a json string containing fields that simply don't match the fields of our Foo object:

@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.

Gson Deserialization Cookbook, How to deserialize Json with the Gson library - a cookbook with the most common scenarios. Explore the options available to exclude fields from serialization in Gson. And unmarshall some json into this type of object: ? Finally, let's see how to force using a specific constructor during deserializations​  Gson can serialize a collection of arbitrary objects but can't deserialize the data without additional information. That's because there's no way for the user to indicate the type of the resulting object. Instead, while deserializing, the Collection must be of a specific, generic type.

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.

Gson Advanced, Of course, this will not be the only post in our Gson series. Special Values of Floats & Doubles the deserialization and combine them to a date object right away. Based on the input JSON you'll have to create your Java model. change serialization for specific types JsonDeserializer<UserDate>  You'll need to implement a single deserialize() method. It passes you a JsonElement, which contains the actual input JSON and the expected type you've to return. Based on the input JSON you'll have to create your Java model. In most cases, Gson can do all of this automatically for you.

Gson User Guide - gson, 5.15 JSON Field Naming Support; 5.16 Sharing State Across Custom Gson is a Java library that can be used to convert Java Objects into their JSON representation. object. While deserializing, Collection must be of a specific generic type The above code fails to interpret value as type Bar because Gson invokes list. Once again, the value changes the default serialization and the default deserialization! Thus, if Gson is creating a JSON from your Java model class, it'll use the value as the name. The alternate are only used as additional option during deserialization. Gson will check the JSON for all names you specify and try to find one to map it to the annotated property.

Gson tutorial, The official Internet media type for JSON is application/json . The toJson() method serializes the specified object into its equivalent JSON representation. Gson by default does not serialize fields with null values to JSON. Gson by default does not serialize fields with null values to JSON. If a field in a Java object is null, Gson excludes it. We can force Gson to serialize null values via the GsonBuilder by using serializeNulls() method.

Deserialization with Gson.fromJson() should *ignore* missing fields , Create a simple *non-static* class which initializes default values for some fields: Create new Gson and call `fromJson()` with missing fields: Test t = new Gson(). Object value) throws IOException, IllegalAccessException { Object fieldValue  In this page, we will learn Serialization and Deserialization between JSON and Java Object for special cases where Gson cannot simply understand class type of format of field. There are different type of cases as below which will be discussed in this page.

Comments
  • Unfortunately because of what is a bad design in terms of the JSON being supplied, what you describe is what you have to do. The answer provided below helps if you can create a class hierarchy in Java that models the data, but that's about as good as you're going to get if that's even applicable.
  • Small tip: instead of setting the properties of the type model manually in the MyTypeModelDeserializer you can also call context.deserialize(json, TypeNModel.class) to use Gson's default deserialization for the actual model. Careful: do not pass MyBaseTypeModel.class as a type since this would result in an infinite deserialization loop. If you register specialized type adapters for your subclasses, they will be invoked as well by the context.deserialize call.
  • To build on what @MartinMatysiak said. A hack-ish way to still be able to use GSON for MyBaseTypeModel you could declare "class MyBaseTypeModelConcrete extends MyBaseTypeModel{}" and then pass MyBaseTypeModelConcrete.class. Not useful in this case but in some cases it can be useful.
  • @DevrimTuncer I have similar question on Gson here. Wanted to see if you can help me out.
  • Wow, much more clean than using JsonDeserializer. It works, thanks.
  • RuntimeTypeAdapterFactory is final. how to extends?
  • I made it non final in my project :-) it's in Gson's extras not in the lib anyway, you can copy it in.
  • According to docs in this file, the factory should not be instantiated directly, but via RuntimeTypeAdapterFactory.of method. Whenever, the answer is generally right and therefore underrated. Thank you.