user3100209
user3100209

Reputation: 367

Jackson Deserialize List of Objects into a Map

I have my own custom deserializer

@Override
public Map<String, Car<?, ?>> deserialize(JsonParser p, DeserializationContext ctxt)
        throws IOException, JsonProcessingException {

    JsonNode carsNode = p.getCodec().readTree(p);
    Map<String, Car<?, ?>> CarsMap = new HashMap<String, Car<?, ?>>();
    ObjectMapper mapper = new ObjectMapper();

    for (JsonNode node : carsNode) {
        CarsMap.put(node.get("name").asText(), mapper.readValue(node.asText(), Car.class));
    }
    return CarsMap;
}

Thought this doesn't work because Car is a base class and the map should have Map String, SubClasses of Cars)

Input JSON = [{"name": "honda", "type": "Regular , "speed": 60}]

this should be in map such as Map.put("honda", RegularCar.class)

Upvotes: 3

Views: 2701

Answers (1)

Manos Nikolaidis
Manos Nikolaidis

Reputation: 22244

You may annotate base Car class to tell Jackson which subclasses to instantiate according to the value of "type" field in JSON. For example if you have RegularCar and ClassicCar extending Car.

@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.PROPERTY, 
    property = "type")
@JsonSubTypes({
    @JsonSubTypes.Type(value = RegularCar.class, name = "Regular"),
    @JsonSubTypes.Type(value = ClassicCar.class, name = "Classic")
})
class Car {

This would allow you to parse like this:

String json = "{\"name\": \"honda\", \"type\": \"Regular , \"speed\": 60}";
Car car = mapper.readValue(json, Car.class);

where Car car actually points to a RegularCar instance. Since the container is declared as Map<String, Car<?, ?>> CarsMap this is exactly what you want to put there and then cast appropriately what you get from the Map.

Upvotes: 2

Related Questions