Jackson:反序列化一个多态列表



我想为我们的REST API实现一个不仅由Java应用程序使用的自定义反序列化器。因此,我不希望Jackson将类型信息放入序列化的JSON中。

我目前正在努力反序列化CollectionExpand,因为它包含特定ResourceModeldata列表。

public class EntityModel<R extends ResourceModel> implements Serializable {
private R data;
private List<ResourceLink> links;
private List<CollectionExpand> expands;
}
public class CollectionExpand {
private String name;
// Resource Model is an interface
private Collection<ResourceModel> data;
}

ResourceModel是一个接口,每个CollectionExpand对每个name包含一种ResourceModel的集合。

例如,json输出可能如下所示:

{
"data": {},
"links": [],
"expand": [
{
"name": "photos",
"data": [
{
"id": 12,
"name": "hello.jpg"
},
{
"id": 12,
"name": "hello.jpg"
}
]
},
{
"name": "persons",
"data": [
{
"id": 783378,
"name": "Peter",
"age": 12
},
{
"id": 273872,
"name": "Maria",
"age": 77
}
]
}
]
}
如您所见,每个名称都包含相同类型的资源模型。photos包含PhotoResourceModel,person包含PersonResourceModel

我开始实现我的自定义Jackson反序列化器

public class CollectionExpandDeserializer extends StdDeserializer<CollectionExpand> {
public CollectionExpandDeserializer() {
super(CollectionExpand.class);
}
@Override
public CollectionExpand deserialize(JsonParser p, DeserializationContext ctxt) throws IOException, JsonProcessingException {
CollectionExpand collectionExpand = new CollectionExpand();
if (Objects.equals(p.nextFieldName(), "name")) {
collectionExpand.setName(p.nextTextValue());
}
if (Objects.equals(p.nextFieldName(), "data")) {
// depending on the field name I would like to delegate the deserialization to a specific type.

if (name.equals("photos") {
// how to do this?
collectionExpand.setData(/* deserialize to a list of PhotoResource */);
}
}

return collectionExpand;
}

我现在正纠结于如何让Jackson将其反序列化为PhotoResource列表。

一般来说,这是正确的方法,还是有另一种方法来做到这一点(不把任何杰克逊元数据到JSON而序列化)?

我最终实现了我的自定义反序列化器,如下所示

@Override
public CollectionExpand deserialize(JsonParser p, DeserializationContext ctx) throws IOException {
JsonNode node = ctx.readTree(p);
CollectionExpand collectionExpand = new CollectionExpand();
collectionExpand.setName(node.get("name").asText());
ArrayNode data = node.withArray("data");
Iterator<JsonNode> iterator = data.iterator();
while (iterator.hasNext()) {
Class<? extends ResourceModel> aClass = resolveClass(collectionExpand.getName());
if (aClass != null) {
JsonNode jsonNode = iterator.next();
collectionExpand.getData().add(p.getCodec().treeToValue(jsonNode, aClass));
}
}
return collectionExpand;
}
private Class<? extends ResourceModel> resolveClass(String name) {
if ("contents".equals(name)) {
return ContentsGetResourceModel.class;
} else if ("tags".equals(name)) {
return TagsGetResourceModel.class;
} else {
return null;
}
}

我花了一些时间来理解如何将JsonNode/TreeNode反序列化为特定类型。最后,我了解到这基本上可以通过使用解析器编解码器来完成。

PhotoResource photoResource = p.getCodec().treeToValue(jsonNode, PhotoResource.class);

最新更新