I have a hierarchy of classes, that I want to use polimorphically in another class. Something like this:
@XmlRootElement // 1 public class Data { @XmlElement private String a; // ... } @XmlRootElement public class DataExt extends Data { @XmlElement private String b; // ... } @XmlRootElement public class Phone { @XmlElement private String type; @XmlElement // 2 private Data data; // ... }1. This is not enough. When JAXB performs the binding, it doesn't care about the runtime class associated to the current object, but it goes straight to the compile time type. We should explicitly say which other classes are part of the hierarchy, using the XmlSeeAlso annotation.
2. We need also to tell to JAXB that it should check the runtime type for this object. This is done by replacing the XmlElement annotation with @XmlElementRef. Actually, at least in my case, this is not a strict necessity. Once specified @XmlSeeAlso on the class definition, JAXB is smart enough to deduce that it has to polimorphically treat the related objects. Still, it adds an attribute to element, in my case xsi:type="dataExt", to show which is the actual type it is using.
So, we'd better change an annotation, and add another one:
@XmlRootElement public class Phone { @XmlElement private String type; @XmlElementRef private Data data; // ... } @XmlRootElement @XmlSeeAlso(DataExt.class) public class Data { @XmlElement private String a; // ... }Besides, I also wanted to keep transparent to the XML user which kind of actual class I used. Meaning that I want the same tag for elements referring to the Data hierarchy. That's very easy. I specify the same name for both XmlRootElement's:
@XmlRootElement(name="data") public class DataExt extends Data { @XmlElement private String b; // ... }