结合 JsonDeserialize#contentAs 与 JsonDeserialize#contentConverter 或 JsonDeserialize#contentUsing 自定义反序列化

Combine JsonDeserialize#contentAs with JsonDeserialize#contentConverter or JsonDeserialize#contentUsing for custom deserialization

JsonDeserialize 注释文档中,contentAs 字段应该定义“反序列化内容的具体类型”。

我尝试将它与 Converter(通过同一注释的 contentConverter 字段)或 JsonDeserializer(通过同一注释的 contentUsing 字段)结合使用,方法是分别扩展 StdConverter 或 StdDeserializer,在尝试创建不可知的自定义反序列化器。 我找不到一种方法来访问这两个 classes 中的任何一个中的 JsonDeserialize#contentAs 信息。

我知道我扩展的 classes 有一个类型参数,我只是把一个对象 class 放在那里。文档状态

contentAs Concrete type to deserialize content (elements of a Collection/array, values of Maps) values as, instead of type otherwise declared. Must be a subtype of declared type; otherwise an exception may be thrown by deserializer.

显然,我正在将 @JsonDeserializer 注释应用于一些可持久化的集合 Class。我想反序列化每个这样的对象,仅仅通过知道它的 id。好吧,如果我只能得到我在 @JsonDeserializer#contentAs 字段中定义的那种类型...

谁能告诉我这是否可行?

毕竟,我设法在不使用 @JsonDeserializer#contentAs 的情况下实现了不可知的反序列化器。

阅读 com.fasterxml.jackson.databind.JsonDeserializer 的 java 文档后,我得出结论,我的自定义反序列化器应该实现 com.fasterxml.jackson.databind.deser.ContextualDeserializer界面.

里面执行ContextualDeserializer#createContextual(DeserializationContext ctxt, BeanProperty 属性) 我终于可以访问集合内容的 class 类型,我在上面应用了 @JsonDeserialize 注释, 致电:

ctxt.getContextualType().getRawClass()

NOTE里面执行的是同一个调用com.fasterxml.jackson.databind.JsonDeserializer#deserialize(com.fasterxml.jackson.core.JsonParser,com.fasterxml.jackson.databind.DeserializationContext) 返回 null,因此需要上述接口。

然后我所要做的就是将返回的 class 存储在自定义反序列化器的成员字段(Class< ? > 类型)中,并在执行 JsonDeserializer#deserialize()

唯一需要检查的是这个自定义解串器的实例是否在线程之间共享。我只做了一些小检查;我对两个不同类型的不同集合使用了相同的实现。我观察到 ContextualDeserializer#createContext(DeserializationContext ctxt, BeanProperty 属性) 被调用一次(在多个反序列化调用中),对于每个将被反序列化的不同类型。调试的时候查了一下,好像是同一个类型用了同一个反序列化器对象。在我的例子中,由于我在成员字段中存储的是这个类型本身,所以我不介意是否使用相同的反序列化器来反序列化 same java 类型因为它们 应该 包含相同的值。所以这方面我们也很清楚。

编辑:看来我所要做的就是将 com.fasterxml.jackson.databind.deser.std.StdDeserializer#_valueClass 值更新为现在已知的 class。由于它是最终的,并且由于 ContextualDeserializer#createContextual(DeserializationContext ctxt, BeanProperty 属性) returns 一个实际使用的 JsonSerializer 对象, 我可以创建一个新序列化器,而不是返回“this”序列化器,在构造函数中传递发现的 class,这实际上设置了 StdDeserializer#_valueClass到我真正想要的class,我已经准备好了!

最后,注意 我不必使用 @JsonDeserializer#contentAs 注释字段,因为我从 ctxt.getContextualType().getRawClass() 里面的语句 ContextualDeserializer#createContextual(DeserializationContext ctxt, BeanProperty 属性) 实施