Подтвердить что ты не робот

Как определить общий десериализатор списка через аннотации с Джексоном?

Скажем, у меня есть объект, который имеет свойства списка:

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 для сопоставления JSON для разных типов карты с Джексоном.

Конечная цель - реализовать пользовательскую десериализующую логику в MyListDeserializer для десериализации пустых строк "" как пустых списков, но я хотел бы узнать об общем подходе, а не только для пустых строк.

4b9b3361

Ответ 1

Вы можете указать класс десериализатора, с помощью которого десериализовать элементы списка с атрибутом 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
            }
        }
     }

Или, если вам нужен один десериализатор для всех типов списков без общего базового класса, используйте атрибут using, MyListDeserializer extend JsonDeserialize<Object>. Для определения типа элемента списка вам придется написать собственный сериализатор, который добавляет информацию о типе в список, который затем может использоваться в универсальном десериализаторе.

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