如何通过Jackson的注释定义通用列表反序列化器?


问题内容

假设我有一个具有列表属性的对象:

public class Citizen {
    name
    List<Tickets> tickets
    List<Fines> fines
}

我想通过注释为列表定义一个通用的自定义反序列化器:

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;
    }
}

我正在寻找一种创建“通用”反序列化器的方法-
一种能够对两种类型的列表进行反序列化的方法,类似于ContextualDeserializer,用于使用Jackson将JSON映射到不同类型的地图。

最终目的是实现自定义反序列化逻辑,MyListDeserializer以将空字符串反序列""化为空列表,但是我想了解一种通用方法,而不仅仅是空字符串。


问题答案:

您可以指定反序列化器类,使用该类对带有注释contentUsing属性的列表元素进行反序列化@JsonDeserializer

public class Citizen {
    ...
    @JsonDeserializer(contentUsing=MyListDeserializer.class) 
    public void setTickets(List<Tickets> tickets) {
        this.tickets = tickets;
    }
}

使解串器扩展,JsonDeserializer<BaseClass>并在BaseClass中具有一个属性,该属性存储具体类的实际类型。

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
            }
        }
     }

或者,如果您要为所有没有通用基类的List类型使用一个反序列化器,则可以使用using属性具有MyListDeserializerextend
JsonDeserialize<Object>。为了确定list元素的类型,您必须编写一个自定义的序列化程序,将类型信息添加到列表中,然后可以在通用反序列化程序中使用它。

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)
    }
}