I want to deserialize a quite complicated set of JSON documents with Jackson. To handle inheritance I implemented some custom deserializers.
To choose the correkt class I have to check the properties of the next node. Therefore I read the tree, check the properties and choose the correct class.
After that I read the JSON via mapper.readerFor(targetClass).readValue(rootNode)
. Everything is fine until here.
But as I use mapper.readerFor(...)
the next called serializer gets an ObjectReader
instance instead of an ObjectMapper
. But I need an ObjectMapper
instance.
How could I do it better?
Here is one of my deserializers, which cause my problem:
public AbstractParametersObject deserialize(JsonParser p, DeserializationContext ctxt)
throws IOException, JsonProcessingException {
Class<? extends AbstractParametersObject> targetClass = null;
ObjectMapper mapper = (ObjectMapper) p.getCodec();
ObjectNode root =mapper.readTree(p);
boolean isReference = root.has("$ref");
boolean isParameter = root.has("in");
if (isReference) targetClass = ParameterAsReference.class;
else if (isParameter) {
targetClass = Optional.of(root.get("in")).map(JsonNode::asText).map(value -> {
Class<? extends AbstractParametersObject> effectiveClass = null;
switch (value) {
case "body": effectiveClass = BodyParameterObject.class;
break;
case "query": effectiveClass = QueryParameterObject.class;
break;
case "path": effectiveClass = PathParameterObject.class;
break;
case "formData": effectiveClass = FormDataParameterObject.class;
break;
case "header": effectiveClass = HeaderParameterObject.class;
break;
}
return effectiveClass;
}).orElseThrow(() -> new IllegalArgumentException("todo"));
}
AbstractParametersObject parametersObject = mapper.readerFor(targetClass)
.readValue(root);
return parametersObject;
}
So the solution was quite simple. Instead calling mapper.readerFor(targetClass).readValue(root)
to deserialize the node tree into an object I had to call mapper.treeToValue(root, targetClass)
.
Here is the working version of the method I posted in my question:
public AbstractParametersObject deserialize(JsonParser p, DeserializationContext ctxt)
throws IOException {
Class<? extends AbstractParametersObject> targetClass = null;
ObjectMapper mapper = (ObjectMapper) p.getCodec();
ObjectNode root =mapper.readTree(p);
boolean isReference = root.has("$ref");
boolean isParameter = root.has("in");
if (isReference) targetClass = ParameterAsReference.class;
} else if (isParameter) {
targetClass = Optional.of(root.get("in")).map(JsonNode::asText).map(value -> {
Class<? extends AbstractParametersObject> effectiveClass = null;
switch (value) {
case "body": effectiveClass = BodyParameterObject.class;
break;
case "query": effectiveClass = QueryParameterObject.class;
break;
case "path": effectiveClass = PathParameterObject.class;
break;
case "formData": effectiveClass = FormDataParameterObject.class;
break;
case "header": effectiveClass = HeaderParameterObject.class;
break;
}
return effectiveClass;
}).orElseThrow(() -> new IllegalArgumentException("todo"));
}
return mapper.treeToValue(root, targetClass);
}