想象一下以下场景:
class <T> Foo<T> {
....
}
class Bar {
Foo<Something> foo;
}
我想为 Foo 编写一个自定义的 Jackson 解串器。为了做到这一点(例如,为了反序列 Bar
具有 Foo<Something>
属性的类),我需要知道使用的 Foo<T>
的具体类型在 Bar
中,在反序列化时(例如,我需要知道 T
是 Something
在这种情况下)。
如何编写这样的反序列化器?应该可以做到,因为 Jackson 使用类型化的集合和地图来做到这一点。
说明:
似乎有两个部分可以解决问题:
1)获取声明的属性类型 foo
内部 Bar
并使用它来反序列 Foo<Somehting>
2)在反序列化时发现我们正在反序列化属性 foo
内部类 Bar
为了成功完成步骤1)
如何完成 1 和 2 ?
原文由 Krešimir Nesek 发布,翻译遵循 CC BY-SA 4.0 许可协议
您可以为您的泛型类型实现自定义
JsonDeserializer
,它也实现ContextualDeserializer
。例如,假设我们有以下包含通用值的简单包装器类型:
我们现在想要反序列化如下所示的 JSON:
进入类的实例,如下所示:
实施
ContextualDeserializer
允许我们根据字段的通用类型参数为Person
类中的每个字段创建一个特定的反序列化器。这允许我们将名称反序列化为字符串,将年龄反序列化为整数。完整的反序列化器如下所示:
最好先在这里查看
createContextual
,因为 Jackson 将首先调用它。我们从BeanProperty
中读取字段的类型(例如Wrapper<String>
),然后提取第一个通用类型参数(例如String
)。然后我们创建一个新的反序列化器并将内部类型存储为valueType
。一旦
deserialize
在这个新创建的反序列化器上被调用,我们可以简单地要求 Jackson 将值反序列化为内部类型而不是整个包装类型,并返回一个新的Wrapper
包含反序列化值。为了注册这个自定义反序列化器,我们需要创建一个包含它的模块,并注册该模块:
如果我们然后尝试反序列化上面的示例 JSON,我们可以看到它按预期工作:
在 Jackson 文档 中有一些关于上下文反序列化器如何工作的更多细节。