Question

I have the following domain model:

@XmlDiscriminatorNode("@type")
class Vehicle

@XmlDiscriminatorValue("car")
class Car extends Vehicle

@XmlDiscriminatorValue("tank")
class Tank extends Vehicle

@XmlDiscriminatorValue("sedan")
class Sedan extends Car

In my top level model class I have a List<Vehicle> that I want to serialize. I want to serialize this model with moxy so that the fields in Sedan show up. When I add XmlDiscriminatorNode to Vehicle and add XmlDiscriminatorValue to the extension classes, only the first level of inheritance is serialized. In the above example, the attributes of Car show up but not the attributes of Sedan. How do I annotate these classes so that Sedan's attributes show up?

Was it helpful?

Solution

When JAXB derives metadata for a model transitive relationships are processed. When a class is processed its super classes are also processed, but not its subclasses. To overcome this you will need to make JAXB aware of the subclasses. One way to do this is to use the @XmlSeeAlso annotation.


Java Model

I will use the Java model from your question with the following changes:

Vehicle

I have added the @XmlSeeAlso annotation. Only the leaf classes need to be added, as processing Sedan will cause the Car class to be processed.

import javax.xml.bind.annotation.XmlSeeAlso;
import org.eclipse.persistence.oxm.annotations.XmlDiscriminatorNode;

@XmlDiscriminatorNode("@type")
@XmlSeeAlso({Tank.class, Sedan.class})
class Vehicle {}

Sedan

I have added a property to the Sedan class to show that it appears in the marshalled result.

import org.eclipse.persistence.oxm.annotations.XmlDiscriminatorValue;

@XmlDiscriminatorValue("sedan")
class Sedan extends Car {

    private String sedanProperty;

    public String getSedanProperty() {
        return sedanProperty;
    }

    public void setSedanProperty(String sedanProperty) {
        this.sedanProperty = sedanProperty;
    }

}

Foo

Here is a root class as you describe in your question that has a List of Vehicle objects.

import java.util.*;
import javax.xml.bind.annotation.*;

@XmlRootElement
public class Foo {

    private List<Vehicle> vehicles = new ArrayList<Vehicle>();

    @XmlElement(name="vehicle")
    public List<Vehicle> getVehicles() {
        return vehicles;
    }


}

Demo Code

Demo

import javax.xml.bind.*;

public class Demo {

    public static void main(String[] args) throws Exception {
        JAXBContext jc = JAXBContext.newInstance(Foo.class);

        Sedan sedan = new Sedan();
        sedan.setSedanProperty("Sedan Value");

        Foo foo = new Foo();
        foo.getVehicles().add(sedan);

        Marshaller marshaller = jc.createMarshaller();
        marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
        marshaller.marshal(foo, System.out);
    }

}

Output

<?xml version="1.0" encoding="UTF-8"?>
<foo>
   <vehicle type="sedan">
      <sedanProperty>Sedan Value</sedanProperty>
   </vehicle>
</foo>
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top