Get nested JSON object with GSON using retrofit-open source projects square/retrofit
@BrianRoach’s solution is the correct solution. It is worth noting that in the special case where you have nested custom objects that both need a custom TypeAdapter
, you must register the TypeAdapter
with the new instance of GSON, otherwise the second TypeAdapter
will never be called. This is because we are creating a new Gson
instance inside our custom deserializer.
For example, if you had the following json:
{
"status": "OK",
"reason": "some reason",
"content": {
"foo": 123,
"bar": "some value",
"subcontent": {
"useless": "field",
"data": {
"baz": "values"
}
}
}
}
And you wanted this JSON to be mapped to the following objects:
class MainContent
{
public int foo;
public String bar;
public SubContent subcontent;
}
class SubContent
{
public String baz;
}
You would need to register the SubContent
‘s TypeAdapter
. To be more robust, you could do the following:
public class MyDeserializer implements JsonDeserializer {
private final Class mNestedClazz;
private final Object mNestedDeserializer;
public MyDeserializer(Class nestedClazz, Object nestedDeserializer) {
mNestedClazz = nestedClazz;
mNestedDeserializer = nestedDeserializer;
}
@Override
public T deserialize(JsonElement je, Type type, JsonDeserializationContext jdc) throws JsonParseException {
// Get the "content" element from the parsed JSON
JsonElement content = je.getAsJsonObject().get("content");
// Deserialize it. You use a new instance of Gson to avoid infinite recursion
// to this deserializer
GsonBuilder builder = new GsonBuilder();
if (mNestedClazz != null && mNestedDeserializer != null) {
builder.registerTypeAdapter(mNestedClazz, mNestedDeserializer);
}
return builder.create().fromJson(content, type);
}
}
and then create it like so:
MyDeserializer myDeserializer = new MyDeserializer(SubContent.class,
new SubContentDeserializer());
Gson gson = new GsonBuilder().registerTypeAdapter(Content.class, myDeserializer).create();
This could easily be used for the nested “content” case as well by simply passing in a new instance of MyDeserializer
with null values.