0

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
  }
}
Thong Vo
  • 809
  • 1
  • 9
  • 21

0 Answers0