您可以
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 AliceSystem.out.println(person.age.value); // prints 37
在Jackson文档中,有更多有关上下文反序列化器如何工作的详细信息。



