-
Notifications
You must be signed in to change notification settings - Fork 21
When using JAXB annotations only, Jackson doesn't include any type metadata for inheritance hierarchies when serializing to JSON (or XML) #71
Description
The situation I face has already been described twice by the same person in two different threads, on Stack Overflow and Google Groups. Unfortunately, it looks like they never raised an issue, so here it goes:
I'm stuck with serializing Beans using Jackson that carry only JAXB annotations, as they're generated from XSD. I have a type hierarchy that basically looks like this (copied from said threads, with the only difference that my ParentClass
also has an @XmlSeeAlso
annotation):
@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(name = "ParentClass", propOrder = { "parentField" })
@XmlSeeAlso( { ChildAClass.class, ChildBClass.class } )
public class ParentClass {
@XmlElement(name = "ParentField")
protected String parentField;
// getters and setters here
}
@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(name = "ChildAClass", propOrder = { "childAfield" })
public class ChildAClass extends ParentClass {
@XmlElement(name = "ChildAfield")
protected String childAfield;
// getters and setters here
}
@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(name = "ChildBClass", propOrder = { "childBfield" })
public class ChildBClass extends ParentClass {
@XmlElement(name = "ChildBfield")
protected String childBfield;
// getters and setters here
}
The resulting JSON basically looks like this when serializing a ChildAClass
:
{
"ChildAfield": "child A field",
"ParentField": "..."
}
and analogously like this when serializing a ChildBClass
:
{
"ChildBfield": "child B field",
"ParentField": "..."
}
The problem is that there's no type metadata generated into the JSON objects, so if one wanted to deserialize this result, one would run into an exception like described in the linked threads:
com.fasterxml.jackson.databind.exc.UnrecognizedPropertyException: Unrecognized field "ChildAfield" (class inheritance.model.ParentClass), not marked as ignorable (one known property: "ParentField"])
at [Source: src/test/resources/testfiles/json/inheritance.json; line: 2, column: 19] (through reference chain: inheritance.model.ParentClass["ChildAfield"])
at com.fasterxml.jackson.databind.exc.UnrecognizedPropertyException.from(UnrecognizedPropertyException.java:79)
at com.fasterxml.jackson.databind.DeserializationContext.reportUnknownProperty( ...
In fact, I'm not deserializing the resulting JSON myself again but this is consumed by an Android client. But the lack of type metadata poses a problem for any consuming client (unless they are willing to/capable of inspecting the properties that are present and deduce the type from that...).
As a sidenote, if I choose to serialize to XML instead of JSON, type metadata is missing all the same.
As suggested in the thread on Google Groups, I added @JsonTypeInfo
manually into the generated classes to see if that works, and indeed this leads to the type metadata being included in the resulting JSON.
I've worked with EclipseLink MOXy before to serialize beans to JSON/XML, therefore I know that there is at least one standard way to include type metadata in XML with JAXB using xsi:type
, which is for example described here. If I use MOXy to serialize to JSON instead of XML with this approach, MOXy merely includes a type
property in the result, too, preserving the type metadata. MOXy also has its own proprietary extensions to control type metadata with @XmlDiscriminatorNode
/@XmlDiscriminatorValue
, and there are other ways still. But it would be nice if Jackson at least produced something by default, if only JAXB annotations can be used.