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.
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 love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With