I have a complex hierarchy of Java interfaces that I\'d like to marshal (and not necessarily unmarshal) with JAXB. These interfaces represent objects that will be returned from
Short answer: use @XmlElement(type = Object.class)
on your interface field.
Details below:
I have found 2 ways in which you could make JAXB serialize your interfaces:
@XmlAnyElement
@XmlElement(type = Object.class)
1.@XmlAnyElement
Simply annotate your interface type field with @XmlAnyElement
and JAXB will serialize the interface from it's concrete type. Don't forget to annotate the concrete types with @XmlRootElement
and to add the concrete types to the JAXBContext. Full example follows:
public class InterfaceSerializer {
@XmlRootElement
public static class Pojo {
Pojo() {
field1 = new PojoFieldImpl1();
field2 = new PojoFieldImpl2();
field3 = new PojoFieldImpl1();
}
@XmlAnyElement
public IPojoField field1;
@XmlAnyElement
public IPojoField field2;
@XmlAnyElement
public IPojoField field3;
@Override
public String toString() {
return "field1 = " + field1 + "\nfield2 = " + field2 + "\nfield3 = " + field3;
}
}
public static interface IPojoField {
}
@XmlRootElement
public static class PojoFieldImpl1 implements IPojoField {
PojoFieldImpl1() {
value = "PojoFieldImpl1 value";
}
public String value;
@Override
public String toString() {
return value;
}
}
@XmlRootElement
public static class PojoFieldImpl2 implements IPojoField {
PojoFieldImpl2() {
value = "PojoFieldImpl2 value1";
value2 = "PojoFieldImpl2 value2";
}
public String value;
public String value2;
@Override
public String toString() {
return value + " " + value2;
}
}
public static void main(String []args) throws JAXBException {
Pojo pojo = new Pojo();
JAXBContext jaxbContext = JAXBContext.newInstance(Pojo.class, PojoFieldImpl1.class, PojoFieldImpl2.class);
Marshaller marshaller = jaxbContext.createMarshaller();
marshaller.marshal(pojo, new File("interfaceSerializer.xml"));
}
}
Output XML:
PojoFieldImpl1 value
PojoFieldImpl2 value1
PojoFieldImpl2 value2
PojoFieldImpl1 value
The downsides of this method:
These downsides are fixed in the second solution:
2.@XmlElement(type = Object.class)
I've stumbled upon this in mikesir87's blog post. Simply replace the @XmlAnyElement
annotations from above with @XmlElement(type = Object.class)
You should have something like this in the Pojo class from above:
@XmlElement(type = Object.class)
public IPojoField field1;
@XmlElement(type = Object.class)
public IPojoField field2;
@XmlElement(type = Object.class)
public IPojoField field3;
Re-running our example, the resulting XML:
PojoFieldImpl1 value
PojoFieldImpl2 value1
PojoFieldImpl2 value2
PojoFieldImpl1 value
This can also be deserialized:
Unmarshaller unmarshaller = jaxbContext.createUnmarshaller();
Pojo unmarshalledPojo = (Pojo) unmarshaller.unmarshal(new File("interfaceSerializer.xml"));
System.out.println(unmarshalledPojo);
Resulting output:
field1 = PojoFieldImpl1 value
field2 = PojoFieldImpl2 value1 PojoFieldImpl2 value2
field3 = PojoFieldImpl1 value
Probably a "hackish" solution, but it gets the job done.