The JAXB system does not look up the classpath for any possible JAXB-annotated classes. You must help him find them. In your code example, it simply does not know about the existence of the Ferrari class. (He sees only Car , because the recipient type is returned in CarTestReport .)
One quick and dirty way to tell JAXB about Ferrari is to add @XmlSeeAlso({Ferrari.class}) to the top of your Car class. Then you will get the result as follows:
<carTestReport> <car xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="ferrari"> <f1Car>false</f1Car> <lastUsed>July 5 2012</lastUsed> </car> <date>July 6 2012</date> <miles>200.0</miles> </carTestReport>
Another way to tell JAXB about Ferrari is to pass this class to the JAXBContext.newInstance method, i.e.:
JAXBContext jaxbContext = JAXBContext.newInstance(CarTestReport.class, Ferrari.class);
Or if all of your JAXB classes are in the same package, for example. com.mycompany.carstuff , you can do this:
JAXBContext jaxbContext = JAXBContext.newInstance("com.mycompany.carstuff");
And in this latter case, it will search for all classes in this package.
If you want it to produce an element named Ferrari (instead of <car xsi:type="ferrari"> as mentioned above), one possibility is to add @XmlType to the top of your Car class, for example:
import javax.xml.bind.annotation.XmlSeeAlso; import javax.xml.bind.annotation.XmlType; @XmlSeeAlso({Ferrari.class}) @XmlType public abstract class Car { public abstract void drive(double miles); }
... and put @XmlRootElement on a Ferrari , for example:
import javax.xml.bind.annotation.XmlRootElement; @XmlRootElement public class Ferrari extends Car {
From what I understand, this combination of annotations tells JAXB that the Car class is mapped to an XML schema type (so you won't get any elements named "car") and that the Ferrari class is an element of this type (so you can have elements named "ferrari"). And the "root" in @XmlRootElement is misleading ... it can be an element anywhere in the structure of your objects.