【问题标题】:Get the detected generic type inside Jackson's JsonDeserializer在 Jackson 的 JsonDeserializer 中获取检测到的泛型类型
【发布时间】:2018-05-01 01:49:16
【问题描述】:

由于外部原因,我系统中的所有 java Maps 只能作为来自客户端的键值对的 列表 接收,例如Map<String, Book> 实际上将作为 Json 序列化的 List<MapEntry<String, Book>> 接收。这意味着我需要自定义我的 Json 反序列化过程以期望这种地图表示。

问题是JsonDeserializer让我实现

deserialize(JsonParser p, DeserializationContext ctxt)

无法访问它应该反序列化的检测到的泛型类型的方法(上面示例中的Map<String, Book>)。如果没有这些信息,我就无法反序列化 List<MapEntry<String, Book>> 而不会失去类型安全性。

我正在查看Converter,但它提供的上下文更少。

例如

public Map<K,V> convert(List<MapToListTypeAdapter.MapEntry<K,V>> list) {
    Map<K,V> x = new HashMap<>();
    list.forEach(entry -> x.put(entry.getKey(), entry.getValue()));
    return x;
}

但这可能会创建危险的地图,在检索时会抛出ClassCastException,因为没有办法检查类型实际上是否合理。 有没有办法解决这个问题?

作为我所期望的示例,Gson 的 JsonDeserializer 如下所示:

T deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context)

即它以一种理智的方式提供对预期类型的​​访问。

【问题讨论】:

  • 您是否因为您的项目使用 Jackson 进行序列化/反序列化而遇到此问题,并且您正在从使用 Moxy 的外部系统获得响应?如果是,那我也有同样的问题。

标签: java json generics jackson jackson-databind


【解决方案1】:

直接从作者那里得到了Jackson Google group的答案。

要理解的关键是 JsonDeserializers 被创建/上下文化一次,并且它们仅在那个时刻接收完整的类型和其他信息。要获取此信息,反序列化器需要实现ContextualDeserializer。它的createContextual 方法被调用来初始化一个反序列化器实例,并且可以访问BeanProperty,这也给出了完整的JavaType

所以它最终可能看起来像这样:

public class MapDeserializer extends JsonDeserializer implements ContextualDeserializer {

    private JavaType type;

    public MapDeserializer() {
    }

    public MapDeserializer(JavaType type) {
        this.type = type;
    }

    @Override
    public JsonDeserializer<?> createContextual(DeserializationContext deserializationContext, BeanProperty beanProperty) throws JsonMappingException {
        //beanProperty is null when the type to deserialize is the top-level type or a generic type, not a type of a bean property
        JavaType type = deserializationContext.getContextualType() != null 
            ? deserializationContext.getContextualType()
            : beanProperty.getMember().getType();            
        return new MapDeserializer(type);
    }

    @Override
    public Map deserialize(JsonParser jsonParser, DeserializationContext deserializationContext) throws IOException {
        //use this.type as needed
    }

    ...
}

注册并正常使用:

ObjectMapper mapper = new ObjectMapper();
SimpleModule module = new SimpleModule();
module.addDeserializer(Map.class, new MapDeserializer());
mapper.registerModule(module);

【讨论】:

  • 我很惊讶以前没有人支持。这个没人用过吗?这个答案是否在其他地方重复?无论如何...非常感谢!
  • @FerranMaylinch 很高兴你发现它有帮助:)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-01-20
  • 2011-10-14
相关资源
最近更新 更多