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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/12937197/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-31 10:51:00  来源:igfitidea点击:

How to define a generic list deserializer through annotations with Hymanson?

javaspringHymanson

提问by ipavlic

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 Hymanson.

我正在寻找一种创建“通用”反序列化器的方法——一种能够反序列化两种类型列表的方法,类似于ContextualDeserializer 用于将 JSON 映射到不同类型的映射与 Hymanson

The final purpose is to implement custom deserializing logic in MyListDeserializerto deserialize empty strings ""as empty lists, but I'd like to know about a general approach, not just for empty strings.

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

回答by Sumit Jain

You can specify the deserializer class with which to deserialize the elements of the list with the contentUsingattribute of the @JsonDeserializerannotation.

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

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.

使您的反序列化器扩展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
            }
        }
     }

Or if you want a single deserializer for all List types with no common base class, then use the usingattribute, have MyListDeserializerextend 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.

或者,如果您想要为没有公共基类的所有 List 类型使用单个反序列化器,则使用using属性,具有MyListDeserializerextend 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)
    }
}