Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Gson - Same field name, different types

Tags:

json

android

gson

I asked this in a different question today but I'm afraid that won't get any solution because of how it was phrased.

I have a json input that has the following data:

Json

As you can see, the option_value item is an Array in one object and a simple string in another object.

How can I make Gson handle this properly? My class has this described as a List object, so it works for the first few items where option_value is an array, but when it becomes a string, the app crashes and I get a json parse exception.

Is there a workaround for this?

UPDATE

Adding the relevant part of my class as requested:

public class Options
    {
        String product_option_id;
        String option_id;
        String name;
        String type;
        String required;
        List<OptionValue> option_value;

        // get set stuff here

        public class OptionValue
        {
            String product_option_value_id;
            String option_value_id;
            String name;
            String image;
            String price;
            String price_prefix;

            // get set stuff here
        }
    }
like image 882
Asim Avatar asked Feb 04 '15 10:02

Asim


People also ask

Does Gson ignore extra fields?

3. Deserialize JSON With Extra Unknown Fields to Object. As you can see, Gson will ignore the unknown fields and simply match the fields that it's able to.

What is serialized name?

The @SerializedName annotation can be used to serialize a field with a different name instead of an actual field name. We can provide the expected serialized name as an annotation attribute, Gson can make sure to read or write a field with the provided name.

What is @expose in Gson?

@Expose is used to allow or disallow serialization and deserialization . @ Expose is optional and it has two configuration parameters: serialize and deserialize . By default they're set to true. To serialize and deserialize with @Expose we create gson object like this. Gson gsonBuilder = new GsonBuilder().

Is Gson better than Jackson?

Conclusion Both Gson and Jackson are good options for serializing/deserializing JSON data, simple to use and well documented. Advantages of Gson: Simplicity of toJson/fromJson in the simple cases. For deserialization, do not need access to the Java entities.


2 Answers

I have a solution for you :) For this purpose, we should use a custom deserializer. Remake your class like this:

    public class Options{

        @SerializedName ("product_option_id");
        String mProductOptionId;

        @SerializedName ("option_id");
        String mOptionId;

        @SerializedName ("name");
        String mName;

        @SerializedName ("type");
        String mType;

        @SerializedName ("required");
        String mRequired;

        //don't assign any serialized name, this field will be parsed manually
        List<OptionValue> mOptionValue;

        //setter
        public void setOptionValues(List<OptionValue> optionValues){
             mOptionValue = optionValues;
        }

        // get set stuff here
        public class OptionValue
        {
            String product_option_value_id;
            String option_value_id;
            String name;
            String image;
            String price;
            String price_prefix;

            // get set stuff here
        }

    public static class OptionsDeserializer implements JsonDeserializer<Options> {

        @Override
        public Offer deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException {
            Options options = new Gson().fromJson(json, Options.class);
            JsonObject jsonObject = json.getAsJsonObject();

            if (jsonObject.has("option_value")) {
                JsonElement elem = jsonObject.get("option_value");
                if (elem != null && !elem.isJsonNull()) {  
                     String valuesString = elem.getAsString();
                     if (!TextUtils.isEmpty(valuesString)){
                         List<OptionValue> values = new Gson().fromJson(valuesString, new TypeToken<ArrayList<OptionValue>>() {}.getType());
                         options.setOptionValues(values);
                     }
                }
            }
            return options ;
        }
    }
    }

Before we can let Gson parse json, we should register our custom deserializer:

    Gson gson = new GsonBuilder()              
                .registerTypeAdapter(Options.class, new Options.OptionsDeserilizer())               
                .create();

And now - just call:

    Options options = gson.fromJson(json, Options.class);
like image 69
Denys Vasylenko Avatar answered Oct 05 '22 08:10

Denys Vasylenko


In my situation, the field with same name is "data":{} or "data":[array_with_real_data]. So the code from accepted answer need to be modified slightly, like this:

@Override
public MyClass deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context)
        throws JsonParseException {
    MyClass bean = new Gson().fromJson(json, MyClass.class);
    JsonObject jsonObject = json.getAsJsonObject();

    if (jsonObject.has("data")) {
        JsonArray array = jsonObject.getAsJsonArray("data");
        if (array != null && !array.isJsonNull()) {
            List<Data> data = new Gson().fromJson(array, new TypeToken<ArrayList<Data>>() {}.getType());
            bean.realData = data;
        }
    }
    return bean ;
}

hope that helps.

like image 35
StoneLam Avatar answered Oct 05 '22 09:10

StoneLam