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.