I need to implement a web service with Retrofit that return an json and map to Java Class. The problem is in the json response will contain a properties that will change detail base on the type of object. Every type has his own specified model, so different fields. How can I map this to the model?
Sample web service response
{
"id": 0,
"code": 0,
"info": {
"type": "ObjectA",
"objId": 1,
"data": [
{
"refId": 1,
"description": "Object A1"
},
{
"refId": 2,
"description": "Object A2"
}
]
}
}
{
"id": 0,
"code": 0,
"info": {
"type": "ObjectB",
"amount": 10,
"value": 20
}
}
{
"id": 0,
"code": 0,
"info": {
"type": "ObjectC",
"name": 10,
"platform": "Android"
}
}
Main result model class
public class Result {
private int id;
private int code;
private AbstractObject info;
}
Abstract class
public abstract class AbstractObject {
private String type;
}
ObjectA class
public class ObjectA extends AbstractObject {
private int objId;
private List<ObjectAInfo> data;
class ObjectAInfo {
private int refId;
private String description;
}
}
ObjectB class
public class ObjectB extends AbstractObject {
private int amount;
private int value;
}
ObjectC class
public class ObjectC extends AbstractObject {
private int name;
private String platform;
}
I need to map the corresponding concrete class of AbstractObject to the Result class base on value of "type".
UPDATED: My solution is extend a JsonDeserializer and register it as a type adapter in the Gson instance.
AbstractObject deserializer class
public class AbstractObjectDeserializer implements JsonDeserializer<AbstractObject> {
@Override
public AbstractObject deserialize(JsonElement jsonElement, Type type, JsonDeserializationContext context)
throws JsonParseException {
JsonObject entry = jsonElement.getAsJsonObject();
switch(entry.get("type").getAsString()) {
case "ObjectA":
return context.deserialize(jsonElement, ObjectA.class);
case "ObjectB":
return context.deserialize(jsonElement, ObjectB.class);
case "ObjectC":
return context.deserialize(jsonElement, ObjectC.class);
default:
throw new IllegalArgumentException("Can't deserialize " + jsonElement);
}
}
}
Register the class in gson instance
gson = new GsonBuilder().registerTypeAdapter(AbstractObject.class, new AbstractObjetcDeserializer()).create();
But it fail to get the right information for the sub class.
{
"id": 0,
"code": 0,
"info": {
"type": "ObjectA"
//Missing all other fields, only get the type from base class
}
}