【问题标题】:How to define a generic list deserializer through annotations with Jackson?如何通过 Jackson 的注释定义通用列表反序列化器?
【发布时间】:2012-10-17 14:56:09
【问题描述】:

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

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 for mapping JSON to different types of maps with Jackson。

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

【问题讨论】:

  • 我认为如果不将您的通用反序列化器子类化以使其具有可靠的类型,这是不可能的。否则,您的反序列化器将不知道它要返回的类型。您可能对@JsonDeserialze 注解的contentAs 属性感兴趣。
  • 解释一下你到底想要达到什么目的怎么样?您是否尝试自定义 List 本身或值的处理?解决方案不同,您可以对其中一个或两个都使用默认处理,也可以都不使用。
  • @StaxMan 我的最终目标类似于我的另一个问题stackoverflow.com/questions/12933394/…。我想简化这个问题,但也许现在没有足够的信息。我会尝试编辑问题。
  • @Dunes 我在地图上看到了类似的东西:stackoverflow.com/questions/6704992/…,所以我认为这是可能的。
  • 好的,所以您确实想更改实际 Collection 的处理方式。

标签: java spring jackson


【解决方案1】:

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

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

让你的反序列化器扩展 JsonDeserializer&lt;BaseClass&gt; 并在 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 属性,将 MyListDeserializer 扩展为 JsonDeserialize&lt;Object&gt;。为了确定列表元素的类型,您必须编写一个自定义序列化程序,将类型信息添加到列表中,然后可以在通用反序列化程序中使用。

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

【讨论】:

  • 是的,但是我必须为我拥有的每种类型的列表制作一个。可以通用吗?
  • 如果您想自定义处理Tickets 类型,您可以使用属性“contentUsing”而不是“using”。
  • 第二种情况是我所追求的。自定义类型添加反序列化器会是什么样子?我希望找到类似于stackoverflow.com/questions/6704992/…
  • 好吧,如果它适用于地图,那么您可以将 Map 替换为 List> & mapper.getTypeFactory().constructMapType(Map.class, String.class, targetType)) 与示例中的 mapper.getTypeFactory().constructCollectionLikeType(List.class,targetType))。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-08-29
  • 2018-03-06
  • 2014-03-11
相关资源
最近更新 更多