How to deserialize abstract subtyped list based on a property

Viewed 102

I have a Cart object that contains a List<Product>, where Product is abstract and should be determined when deserializing the object, based upon the value of Cart.channel.

Cart:

public class Cart {
    Channel channel; // Either Channel.ONLINE or Channel.PRINT
    List<? extends Product>; // Either List of OnlineProduct or PrintProduct
}

I tried to write a custom Deserializer that simply uses a plain ObjectMapper to deserialize the nested property based upon the channel, but the Cart object has many more properties in reality and I don't want to extend the Deserializer every time I extend the Cart object.

Working with @JsonSubTypes as supposed in Deserializing json subtype based on parent property also didn't do the trick, since the property is a List instance:

public class Cart {
    Channel channel; // Either Channel.ONLINE or Channel.PRINT

    @JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.EXTERNAL_PROPERTY, property = "channel")
    @JsonSubTypes(value = {
            @JsonSubTypes.Type(value = SalesProductOnsite.class, name = "onsite"),
            @JsonSubTypes.Type(value = SalesProductPrint.class, name = "print")
    })
    List<Product>; // Either List of OnlineProduct or PrintProduct
}

I also tried to ignore the field at runtime and then use the correct mapping, but to no avail:

public class CartDeserializer extends JsonDeserializer<Cart> {

    private final ObjectMapper objectMapper = new ObjectMapper();

    @Override
    public Cart deserialize(JsonParser jsonParser, DeserializationContext ctxt) throws IOException {
        Cart c = objectMapper.reader().withoutAttribute("products").readValue(jsonParser, Cart.class);
        if(cart.channel == Channel.ONLINE) {
            // cart.products = objectMapper.readValue(...)
        } else {
            // cart.products = objectMapper.readValue(...)
        }

        return cart;
    }
}
0 Answers
Related