简体   繁体   中英

Gson custom deseralizer for one variable in an object

My probelm example:

We have an object type of Apple. Apple has some member variables:

String appleName; // The apples name
String appleBrand; // The apples brand
List<Seed> seeds; // A list of seeds the apple has

And the seed object looks as follows.

String seedName; // The seeds name
long seedSize; // The size of the seed

Now When I get an apple object, an apple could have more than one seed, or it could have one seed, or maybe no seeds!

Example JSON apple with one seed:

{
"apple" : {
   "apple_name" : "Jimmy", 
   "apple_brand" : "Awesome Brand" , 
   "seeds" : {"seed_name":"Loopy" , "seed_size":"14" }
  }
}

Example JSON apple with two seeds:

{
"apple" : {
   "apple_name" : "Jimmy" , 
   "apple_brand" : "Awesome Brand" , 
   "seeds" : [ 
      { 
         "seed_name" : "Loopy",
         "seed_size" : "14"
      },
      {
         "seed_name" : "Quake",
         "seed_size" : "26"
      } 
  ]}
}

Now the issue here is the first example is a JSONObject for seeds, the second example is a JSONArray for seeds. Now I know its inconsistent JSON and the easiest way to fix it would be fix the JSON itself, but unfortunately I'm getting the JSON from some one else, so I cant fix it. What would be the easiest way to fix this issue?

You need to register a custom type adapter for the Apple type. In the type adapter, you will add logic to determine if you were given an array or a single object. Using that info, you can create your Apple object.

In adition to the below code, modify your Apple model object so that the seeds field isn't automatically parsed. Change the variable declaration to something like:

private List<Seed> seeds_funkyName;

Here is the code:

GsonBuilder b = new GsonBuilder();
b.registerTypeAdapter(Apple.class, new JsonDeserializer<Apple>() {
    @Override
    public Apple deserialize(JsonElement arg0, Type arg1,
        JsonDeserializationContext arg2) throws JsonParseException {
        JsonObject appleObj = arg0.getAsJsonObject();
        Gson g = new Gson();
        // Construct an apple (this shouldn't try to parse the seeds stuff
        Apple a = g.fromJson(arg0, Apple.class);
        List<Seed> seeds = null;
        // Check to see if we were given a list or a single seed
        if (appleObj.get("seeds").isJsonArray()) {
            // if it's a list, just parse that from the JSON
            seeds = g.fromJson(appleObj.get("seeds"),
                    new TypeToken<List<Seed>>() {
                    }.getType());
        } else {
            // otherwise, parse the single seed,
            // and add it to the list
            Seed single = g.fromJson(appleObj.get("seeds"), Seed.class);
            seeds = new ArrayList<Seed>();
            seeds.add(single);
        }
        // set the correct seed list
        a.setSeeds(seeds);
        return a;
    }
});

For some more info, see the Gson guide .

We are using arrays instead of Lists with GSON, and there is no such problem: look at http://app.ecwid.com/api/v1/1003/product?id=4064 the "categories" property is actually an Javascript array with one element. It was declared like this:

Category[] categories;

UPdate: using TypeToken and Custom Serialization might help, see this doc: https://sites.google.com/site/gson/gson-user-guide

I faced the same problem. I think my solution is slightly simpler and more generic:

Gson gson = new GsonBuilder()
        .registerTypeAdapter(List.class, new JsonSerializer<List<?>>() {
            @Override
            public JsonElement serialize(List<?> list, Type t,
                    JsonSerializationContext jsc) {
                if (list.size() == 1) {
                    // Don't put single element lists in a json array
                    return new Gson().toJsonTree(list.get(0));
                } else {
                    return new Gson().toJsonTree(list);
                }
            }
        }).create();

Of course, I agree with the original poster, the best solution is to change the json. There is nothing wrong with an array of size 1 and it would keep serializing and de-serializing much simpler! Unfortunately, sometimes these changes are out of your control.

If you can't change the JSON (as you getting it from someone else) then the Simplest solution is to change your Apple and Seed class variable name in Java Class so that it matches with the parsed JSON.

Change it to :

Apple Class
-----------
String apple_name; // The apples name
String apple_brand; // The apples brand
List<Seed> seeds; // A list of seeds the apple has
And the seed object looks as follows.

Seed Class
-----------
String seed_name; // The seeds name
long seed_size; // The size of the seed

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM