Reputation: 1184
I use Jackson to create JSON for polymorphic objects using an annotation in the ancestor class:
// Include Java class name ("com.myempl.ImplClass") as JSON property "class"
@JsonTypeInfo(use=Id.CLASS, include=As.PROPERTY, property="class")
Using this annotation, the descendant classes will have the class
property with the class name of the object. This class name will be used when Jackson converts back JSON object to the correct descendant.
When using JAX-B with
@XmlSeeAlso({Class1, Class2, ... ClassN })
annotation, you have to specify all the subclasses of the element if you want correct unmarshalling, or you should add all elements to the JAXBContext
, when creating a new JAXBContext
instance.
Is there a way to specify the object class name to JAX-B just like with Jackson? If there's no way, why?
Upvotes: 2
Views: 3378
Reputation: 148977
I believe you are looking for the @XmlType
annotation. Below is an example of how it can be used:
Root
import java.util.*;
import javax.xml.bind.annotation.*;
@XmlRootElement
public class Root {
private List<AbstractClass> classes = new ArrayList<AbstractClass>();
@XmlElement(name="class")
public List<AbstractClass> getClasses() {
return classes;
}
}
AbstactClass
We will use the @XmlSeeAlso
annotation to cause Class1
and Class2
to be processed when the metadata is being figured out. Java does not provide a mechanism to reflectively access the subclasses for a class.
import javax.xml.bind.annotation.XmlSeeAlso;
@XmlSeeAlso({Class1.class, Class2.class})
public class AbstractClass {
}
Class1
By default each class has a class indicator name derived for the short class name.
public class Class1 extends AbstractClass {
}
Class2
We can use the @XmlType
annotation to override the class indicator name.
import javax.xml.bind.annotation.XmlType;
@XmlType(name="class-two")
public class Class2 extends AbstractClass {
}
Demo
Below we will create an instance of Root
and set instances of Class1
and Class2
on the classes
property which is of the super type AbstractClass
.
import javax.xml.bind.*;
public class Demo {
public static void main(String[] args) throws Exception {
JAXBContext jc = JAXBContext.newInstance(Root.class);
Root root = new Root();
root.getClasses().add(new Class1());
root.getClasses().add(new Class2());
Marshaller marshaller = jc.createMarshaller();
marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
marshaller.marshal(root, System.out);
}
}
Output
The value for the xsi:type
for the instance of Class1
was derived from the class name, and the value for the instance of Class2
corresponds to the name we set on the @XmlType
annotation.
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<root>
<class xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="class1"/>
<class xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="class-two"/>
</root>
Upvotes: 1