Let's say I have an object which has list properties:
public class Citizen {
name
List<Tickets> tickets
List<Fines> fines
}
I'd like to define a generic custom deserializer for lists through annotations:
public class Citizen {
...
@JsonDeserializer(MyListDeserializer<Tickets>) // <-- generic deserializer
public void setTickets(List<Tickets> tickets) {
this.tickets = tickets;
}
@JsonDeserializer(MyListDeserializer<Fines>) // <-- how can I do that?
public void setFines(List<Fines> fines) {
this.fines = fines;
}
}
I'm looking for a way to create a "generic" deserializer — one that would be able to deserialize both types of lists, similar to ContextualDeserializer for mapping JSON to different types of maps with Jackson.
The final purpose is to implement custom deserializing logic in MyListDeserializer
to deserialize empty strings ""
as empty lists, but I'd like to know about a general approach, not just for empty strings.
You can specify the deserializer class with which to deserialize the elements of the list
with the contentUsing
attribute of the @JsonDeserializer
annotation.
public class Citizen {
...
@JsonDeserializer(contentUsing=MyListDeserializer.class)
public void setTickets(List<Tickets> tickets) {
this.tickets = tickets;
}
}
Make your deserializer extend JsonDeserializer<BaseClass>
and have a attribute in the BaseClass that stores the actual type of the concrete class.
abstract class BaseTickets {
String ticketType;
public String getTicketType()
}
public class MyListDeserializer extends JsonDeserializer<BaseTickets> {
@Override
public BaseTickets deserialize(JsonParser jsonParser, DeserializationContext arg1) throws IOException, JsonProcessingException {
ObjectCodec oc = jsonParser.getCodec();
JsonNode node = oc.readTree(jsonParser);
Iterator<JsonNode> elements = node.getElements();
for (; elements.hasNext();) {
String type = (String) elements.next().get("ticketType");
if (type.equals()){
//create concrete type here
}
}
}
Or if you want a single deserializer for all List types with no common base class, then use the using
attribute, have MyListDeserializer
extend JsonDeserialize<Object>
. For determining the type of list element you would have to write a custom serializer that adds the type information to the list which can then be used in the generic deserializer.
public class Citizen {
...
@JsonDeserializer(using=MyListDeserializer.class)
@JsonSerializer(using=MyListSerializer.class)
public void setTickets(List<Tickets> tickets) {
this.tickets = tickets;
}
}
public class MyListSerializer extends JsonSerializer<Object> {
@Override
public void serialize(Object list, JsonGenerator jgen, SerializerProvider provider) throws IOException, JsonProcessingException {
@SuppressWarnings("rawtypes")
jgen.writeStartObject();
String type = getListType(list);
jgen.writeStringField("listType", type);
jgen.writeObjectField("list", list)
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With