想象以下情况:
class <T> Foo<T> {
....
}
class Bar {
Foo<Something> foo;
}
我想为Foo写一个自定义的Jackson解串器。为了做到这一点(例如,为了反序列化Bar
类,它具有Foo<Something>
属性),我需要知道的具体类型Foo<T>
,在使用Bar
,在反序列化时间(比如我需要知道T
是Something
在particluar情况下)。
一个人怎么写这样的反序列化器?因为杰克逊使用类型化的集合和地图来做到这一点,所以应该有可能做到这一点。
说明:
似乎有两个部分可以解决问题:
1)获取foo
内部声明的属性类型Bar
并使用其反序列化Foo<Somehting>
2)在反序列化时发现我们正在对foo
类内部的属性进行反序列化Bar
,以便成功完成步骤1)
一个如何完成1和2?
您可以JsonDeserializer
为自己的通用类型实现自定义,该自定义类型也可以实现ContextualDeserializer
。
例如,假设我们具有以下包含通用值的简单包装器类型:
public static class Wrapper<T> {
public T value;
}
现在,我们要反序列化如下所示的JSON:
{
"name": "Alice",
"age": 37
}
变成一个看起来像这样的类的实例:
public static class Person {
public Wrapper<String> name;
public Wrapper<Integer> age;
}
实现ContextualDeserializer
使我们能够Person
基于字段的通用类型参数为类中的每个字段创建特定的反序列化器。这使我们可以将名称反序列化为字符串,将年龄反序列化为整数。
完整的解串器如下所示:
public static class WrapperDeserializer extends JsonDeserializer<Wrapper<?>> implements ContextualDeserializer {
private JavaType valueType;
@Override
public JsonDeserializer<?> createContextual(DeserializationContext ctxt, BeanProperty property) throws JsonMappingException {
JavaType wrapperType = property.getType();
JavaType valueType = wrapperType.containedType(0);
WrapperDeserializer deserializer = new WrapperDeserializer();
deserializer.valueType = valueType;
return deserializer;
}
@Override
public Wrapper<?> deserialize(JsonParser parser, DeserializationContext ctxt) throws IOException {
Wrapper<?> wrapper = new Wrapper<>();
wrapper.value = ctxt.readValue(parser, valueType);
return wrapper;
}
}
最好先看createContextual
这里,因为这将由杰克逊首先调用。我们从中读取字段的类型BeanProperty
(例如Wrapper<String>
),然后提取第一个通用类型参数(例如String
)。然后,我们创建一个新的反序列化器并将内部类型存储为valueType
。
一旦deserialize
调用了这个新创建的反序列化器,我们可以简单地要求Jackson将值反序列化为内部类型而不是整个包装器类型,然后返回一个Wrapper
包含反序列化值的新值。
为了注册此自定义反序列化器,我们需要创建一个包含它的模块,然后注册该模块:
SimpleModule module = new SimpleModule()
.addDeserializer(Wrapper.class, new WrapperDeserializer());
ObjectMapper objectMapper = new ObjectMapper();
objectMapper.registerModule(module);
然后,如果我们尝试从上面反序列化示例JSON,则可以看到它按预期工作:
Person person = objectMapper.readValue(json, Person.class);
System.out.println(person.name.value); // prints Alice
System.out.println(person.age.value); // prints 37
在Jackson文档中,有更多有关上下文反序列化器如何工作的详细信息。
本文收集自互联网,转载请注明来源。
如有侵权,请联系[email protected] 删除。
我来说两句