0

I have a Vehicle interface which Car and Bus implement. The server returns a response like this -

{
    "id" : 10,
    "vehicle_type" : "Car",
    "vehicle" : {
          "id"  : 100,
          "name" : "MyCar"
    }
    // More attributes.
}

The corresponding class to model it is

class Response {
    int id;
    String vehicle_type;
    Vehicle vehicle;
    // More attributes.
}

The vehicle_type in the response declares what kind of vehicle it is. I need to deserialize the response into a Response object depending on the vehicle_type. If it is Car I need to use Car.class for deserializing vehicle during the deserialization of response and Bus.class if it is otherwise.

How can I achieve this using gson?

EDIT - This post is different in the sense that class type(type) is contained within the jsonobject that needs to deserialized. Here it is not. If vehicle_type was inside vehicle, I could write a custom deserializer for Vehicle, check the vehicle_type and deserialize accordingly. But I think I would need to write a custom deserializer for Response where I create a new Response object, parse vehicle_type, deserialize it into a Vehicle object accordingly and add it and rest of attributes of response to the Response object manually by parsing them. This is very cumbersome and using gson doesn't really help then. I was hoping for a better solution. :)

Community
  • 1
  • 1
aandis
  • 4,084
  • 4
  • 29
  • 40
  • 1
    Have you read this thread? http://stackoverflow.com/questions/21767485/gson-deserialization-to-specific-object-type-based-on-field-value – Robbenu Aug 27 '15 at 11:02
  • @Rob I just did. Please check the edit. – aandis Aug 27 '15 at 11:14
  • @zack follow the same model as the earlier post for Response and within it use `context.deserialize()` for Car/Bus - you don't need to do it manually. See the comment on the accepted answer. – Dakshinamurthy Karra Aug 27 '15 at 11:24
  • @KDM I meant I would have to add the other attributes of `response` to the object manually. – aandis Aug 27 '15 at 11:50
  • @zack I don't know much about jackson. This http://stackoverflow.com/questions/18313323/how-do-i-call-the-default-deserializer-from-a-custom-deserializer-in-jackson might help. Something like use default serializer to serialise the Response object and do some more extra work. – Dakshinamurthy Karra Aug 27 '15 at 12:22
  • @KDM I ended up doing exactly that. I'll post an answer. – aandis Aug 27 '15 at 13:06

1 Answers1

0

So I wrote a custom deserializer for Response where I first invoke the default deserializer, get the vehicle type and do Vehicle deserialization accordingly.

public Response deserialize(JsonElement jsonElement, Type type, JsonDeserializationContext jsonDeserializationContext) throws JsonParseException {
    Response response = new Gson().fromJson(jsonElement, Response.class);
    Type t = null;
    if (response.getVehicleType().equals(Bus.vehicle_type)) {
        t = Bus.class;
    } else if (response.getVehicleType().equals(Car.vehicle_type)) {
        t = Car.class;
    }
    JsonObject object = jsonElement.getAsJsonObject();
    if (object.has("vehicle")) {
        JsonElement vehicleElement = object.get("vehicle");
        Vehicle vehicle = jsonDeserializationContext.deserialize(vehicleElement, t);
        response.setVehicle(vehicle);
    }
    return response;
}

Looking forward to better solutions. :)

aandis
  • 4,084
  • 4
  • 29
  • 40