Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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?

like image 783
fbl Avatar asked Dec 02 '11 13:12

fbl


1 Answers

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

  • http://blog.bdoughan.com/2010/11/jaxb-and-inheritance-using-substitution.html
like image 94
bdoughan Avatar answered Sep 25 '22 01:09

bdoughan