Kre*_*sek 15 java generics json jackson deserialization
想象一下以下场景:
class <T> Foo<T> {
....
}
class Bar {
Foo<Something> foo;
}
Run Code Online (Sandbox Code Playgroud)
我想为Foo编写一个自定义Jackson解串器.为了做到这一点(例如,为了反序列化Bar具有类Foo<Something>属性),我需要知道具体类型的Foo<T>,在使用Bar,在反序列化时间(比如我需要知道T是Something在particluar情况下).
如何编写这样的解串器?应该可以这样做,因为杰克逊用类型集合和地图来做.
澄清:
似乎有2个部分来解决问题:
1)获取foo内部声明的属性类型Bar并使用它来反序列化Foo<Somehting>
2)在反序列化时找出我们正在对foo类内的属性进行反序列化Bar以便成功完成步骤1)
如何完成1和2?
and*_*ler 37
您可以JsonDeserializer为也实现的泛型类型实现自定义ContextualDeserializer.
例如,假设我们有以下包含通用值的简单包装器类型:
public static class Wrapper<T> {
public T value;
}
Run Code Online (Sandbox Code Playgroud)
我们现在想要反序列化看起来像这样的JSON:
{
"name": "Alice",
"age": 37
}
Run Code Online (Sandbox Code Playgroud)
进入如下所示的类的实例:
public static class Person {
public Wrapper<String> name;
public Wrapper<Integer> age;
}
Run Code Online (Sandbox Code Playgroud)
实现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;
}
}
Run Code Online (Sandbox Code Playgroud)
最好先看一下createContextual,因为这将首先由杰克逊召集.我们从BeanProperty(例如Wrapper<String>)中读取字段的类型,然后提取第一个泛型类型参数(例如String).然后我们创建一个新的反序列化器并将内部类型存储为valueType.
一旦deserialize在这个新创建的反序列化器上调用,我们可以简单地要求Jackson将值反序列化为内部类型而不是整个包装类型,并返回Wrapper包含反序列化值的new .
为了注册这个自定义反序列化器,我们需要创建一个包含它的模块,并注册该模块:
SimpleModule module = new SimpleModule()
.addDeserializer(Wrapper.class, new WrapperDeserializer());
ObjectMapper objectMapper = new ObjectMapper();
objectMapper.registerModule(module);
Run Code Online (Sandbox Code Playgroud)
如果我们尝试从上面反序列化示例JSON,我们可以看到它按预期工作:
Person person = objectMapper.readValue(json, Person.class);
System.out.println(person.name.value); // prints Alice
System.out.println(person.age.value); // prints 37
Run Code Online (Sandbox Code Playgroud)
关于上下文反序列化器如何在Jackson文档中工作的更多细节.
如果目标本身是泛型类型,则属性将为空,为此您需要从 DeserializationContext 获取 valueTtype:
@Override
public JsonDeserializer<?> createContextual(DeserializationContext ctxt, BeanProperty property) throws JsonMappingException {
if (property == null) { // context is generic
JMapToListParser parser = new JMapToListParser();
parser.valueType = ctxt.getContextualType().containedType(0);
return parser;
} else { // property is generic
JavaType wrapperType = property.getType();
JavaType valueType = wrapperType.containedType(0);
JMapToListParser parser = new JMapToListParser();
parser.valueType = valueType;
return parser;
}
}
Run Code Online (Sandbox Code Playgroud)