Let there be an abstract class A with a property a and three non-abstract subclasses B, C and D. B has no additional property, C contains the property c and D contains both properties c and d.
I would like to subclass StdDeserializer for the abstract class A to be able to decide based on the existence of properties to be deserialized which subclass to choose.
I did that with some Jackson release from Codehaus before and it was working fine using the following implementation:
class AbstractADeserializer extends StdDeserializer<A> {
AbstractADeserializer () {
super(A.class);
}
@Override
public A deserialize(JsonParser jp, DeserializationContext ctxt)
throws IOException, JsonProcessingException {
ObjectMapper mapper = (ObjectMapper) jp.getCodec();
ObjectNode root = (ObjectNode) mapper.readTree(jp);
Class<? extends A> requestClass = null;
// root.getFieldNames() is an iterator over all field names
JsonNode cValue = root.findValue("c");
JsonNode dValue = root.findValue("d");
/*
* Check for existence of required fields and choose the
* corresponding request class.
*/
logger.debug(Boolean.toString(c != null));
logger.debug(Boolean.toString(d != null));
if(c != null && d == null) {
logger.debug("Found C");
requestClass = C.class;
} else if(c != null && d != null) {
logger.debug("Found D");
requestClass = D.class;
} else {
logger.debug("Found B");
requestClass = B.class;
}
return mapper.readValue(root, requestClass);
}
}
This worked fine but after migration to Jackson 2.4 from FasterXML ObjectMapper does not allow ObjectNode as a parameter for it's readValue
method.
When I modified the code to use return mapper.readValue(jp, requestClass); I always get
com.fasterxml.jackson.databind.JsonMappingException: No content to map due to end-of-input
at [Source: org.apache.catalina.connector.CoyoteInputStream@1286ec89; line: 1, column: 559]
at com.fasterxml.jackson.databind.JsonMappingException.from(JsonMappingException.java:148)
at com.fasterxml.jackson.databind.ObjectMapper._initForReading(ObjectMapper.java:3095)
at com.fasterxml.jackson.databind.ObjectMapper._readValue(ObjectMapper.java:3009)
at com.fasterxml.jackson.databind.ObjectMapper.readValue(ObjectMapper.java:1637)
What alternatives do you see the flexible determine the class of a given input without needing to deserialize the object manually? To me it looks complicated to clone the JsonParser to avoid the exhaustion of it's input source.
Just ran into similar issues, and for me it was all fixed by replacing mapper.readValue(jp, requestClass)
with mapper.treeToValue(root, requestClass)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With