Asim
Asim

Reputation: 7114

Gson - Same field name, different types

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

Upvotes: 34

Views: 21854

Answers (2)

Denys Vasylenko
Denys Vasylenko

Reputation: 2143

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

Upvotes: 32

StoneLam
StoneLam

Reputation: 400

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.

Upvotes: 6

Related Questions