您可以为泛型类型实现自定义 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;
}
实现允许我们根据字段的泛型类型参数为类中的每个字段创建一个特定的反序列化程序。这允许我们将名称反序列化为字符串,并将 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
一旦在这个新创建的反序列化器上被调用,我们就可以简单地要求Jackson将值反序列化为内部类型而不是整个包装器类型,并返回一个包含反序列化值的新值。deserialize
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 文档中有一些关于上下文反序列化器如何工作的更多详细信息。