获取Jackson的JsonDeserializer中检测到的泛型类型

b5buobof  于 2022-11-08  发布在  其他
关注(0)|答案(1)|浏览(261)

由于外部原因,我的系统中的所有java Map只能从客户端以键-值对的 * 列表 * 形式接收,例如,Map<String, Book>实际上将以JSON序列化的List<MapEntry<String, Book>>形式接收。这意味着我需要自定义Json反序列化过程,以获得这种Map表示。
问题是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;
}

但这可能会创建危险的Map,在检索时会抛出ClassCastException,因为没有办法检查类型是否实际上是合理的。有办法解决这个问题吗?
作为一个我所期望的例子,Gson的JsonDeserializer看起来像这样:

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

也就是说,它以一种正常的方式提供对预期类型的访问。

5f0d552i

5f0d552i1#

直接从作者那里得到了Jackson谷歌组的答案。
要理解的关键是**JsonDeserializer只被初始化/上下文化一次**,它们只在那一刻接收完整的类型和其他信息。为了获得这些信息,反序列化器需要实现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);

相关问题