fbl
fbl

Reputation: 2906

Can JAXB initialize values in base classes?

I am working on a Scala project, and we want to use XML to initialize our objects with JAXB (not Spring). I have a hierarchy where more data members get added in the subclasses. A simple example would look something like this:

class Animal
{
   string name
}

class Cat extends Animal
{
   int numLives
}

class Dog extends Animal
{
   bool hasSpots
}

I would like to be able to initialize a list of animals from an XML block that looks something like this:

<Animals>
   <Cat>
      <name>Garfield</name>
      <numLives>9</numLives>
   </Cat>
   <Dog>
      <name>Odie</name>
      <hasSpots>false</hasSpots>
   </Dog>
</Animals>

How would we setup the annotations in the classes to be able to handle this?

Upvotes: 6

Views: 1820

Answers (2)

bdoughan
bdoughan

Reputation: 149037

For this example you will want to make use of the @XmlElementRef and @XmlRootElement annotations. This corresponds to the XML schema concept of substitution groups. This will allow you to have a list of objects from an inheritance hierarchy differentiated by element.

Animals

This will serve as the root object for the domain model. It has a List property annotated with @XmlElementRef. This means it will match values based on the value of their @XmlRootElement annotations.

package forum8356849;

import java.util.List;

import javax.xml.bind.annotation.*;

@XmlRootElement(name="Animals")
@XmlAccessorType(XmlAccessType.FIELD)
@XmlSeeAlso({Cat.class, Dog.class})
public class Animals {

    @XmlElementRef
    private List<Animal> animals;
}

Animal

package forum8356849;

import javax.xml.bind.annotation.*;

@XmlAccessorType(XmlAccessType.FIELD)
class Animal
{
   String name;
}

Cat

We will annotate the Cat class with an @XmlRootElement annotation. This is used in tandem with the @XmlElementRef annotation on Animals.

package forum8356849;

import javax.xml.bind.annotation.*;

@XmlRootElement(name="Cat")
class Cat extends Animal
{
   int numLives;
}

Dog

We will also add an @XmlRootElement annotation to the Dog class.

package forum8356849;

import javax.xml.bind.annotation.*;

@XmlRootElement(name="Dog")
class Dog extends Animal
{
   boolean hasSpots;
}

Demo

You can use the following class to see that everything works as expected. input.xml corresponds to the XML provided in your question.

package forum8356849;

import java.io.File;
import javax.xml.bind.*;

public class Demo {

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

        Unmarshaller unmarshaller = jc.createUnmarshaller();
        File xml = new File("src/forum8356849/input.xml");
        Animals animals = (Animals) unmarshaller.unmarshal(xml);

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

}

For More Inforation

Upvotes: 3

belgther
belgther

Reputation: 2534

In such cases, I prefer creating an XSD schema and generating code from it, so you are on safe side. But to answer your question, yes, you can. The annotations are XMLElement, XMLAttribute, XMLRootElement.

Upvotes: 0

Related Questions