Tuesday 7 August 2012

JAXB Annotation - JAXB Context, Generics

Understanding JAXB Context

In order to marshall and unmarshall JAXB annotated classes, one needs to create a JAXBContext. The instantiator method takes in a list of JAXB annotated Class.

By default, JAXB will include statically referenced classes in the list and inherited classes, but not transient or inheriting classes. The code examples are available from Github in the JAXB-JSON-XML-Marshalling directory.

Assuming:
@XmlRootElement
public class StaticallyReferenced {

    private String data;

    @XmlElement
    public String getData() {
        return data;
    }

    public void setData(String data) {
        this.data = data;
    }
    
}

@XmlRootElement
public class StaticallyReferencedButTransient {
    
    private String data;

    @XmlElement
    public String getData() {
        return data;
    }

    public void setData(String data) {
        this.data = data;
    }
    
}

@XmlRootElement
public class SomeA {
    
    private StaticallyReferenced sr;
    private StaticallyReferencedButTransient srbt;

    @XmlElement
    public StaticallyReferenced getSr() {
        return sr;
    }

    public void setSr(StaticallyReferenced sr) {
        this.sr = sr;
    }

    @XmlTransient
    public StaticallyReferencedButTransient getSrbt() {
        return srbt;
    }

    public void setSrbt(
            StaticallyReferencedButTransient srbt) {
        this.srbt = srbt;
    }

}

@XmlRootElement
public class InheritSomeA extends SomeA {
    
    private String moreData;

    @XmlElement
    public String getMoreData() {
        return moreData;
    }

    public void setMoreData(String moreData) {
        this.moreData = moreData;
    }
    
}
If one creates the following JAXB context:
JAXBContext jaxbContext =
    JAXBContext.newInstance(SomeA.class);
JAXB will only be able to process SomeA and StaticallyReferenced, not StaticallyReferencedButTransient or InheritSomeA.

How to use JAXB with Generics such as List, Set, etc...?

Assuming a simple example, where an object contains a List<String>:
@XmlRootElement
public class ObjectWithList {

    private List<String> list;

    @XmlElementWrapper(name="MyList")
    @XmlElement
    public List<String> getList() {
        return list;
    }

    public void setList(List<String> list) {
        this.list = list;
    }

}
If the JAXB context is built as following (before a round trip):
public static void simpleExample() throws JAXBException {

    List<String> l = new ArrayList<String>();
    l.add("Somewhere");
    l.add("This and that");
    l.add("Something");

    // Object with list
    ObjectWithList owl = new ObjectWithList();
    owl.setList(l);

    JAXBContext jc = JAXBContext.newInstance(ObjectWithList.class);
    ObjectWithList retr = marshallUnmarshall(owl, jc);

    for (String s : retr.getList()) {
        System.out.println(s);
    } System.out.println(" ");

}
The generated XML with verification is:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<objectWithList>
    <MyList>
        <list>Somewhere</list>
        <list>This and that</list>
        <list>Something</list>
    </MyList>
</objectWithList>

Somewhere
This and that
Something
A more sophisticated example with a generic list:
@XmlRootElement
public class ObjectWithGenericList<T> {

    private List<T> myList;

    @XmlElementWrapper(name="MyGenericList")
    @XmlElement
    public List<T> getList() {
        return myList;
    }

    public void setList(List<T> list) {
        this.myList = list;
    }

}
used with the following JAXB context and verification:
public static void genericListExample()
        throws JAXBException {

    List<Car> l = new ArrayList<Car>();
    l.add(new Car("red car"));
    l.add(new Car("blue car"));
    l.add(new Car("green car"));

    // Object with generic list
    ObjectWithGenericList<Car> owgl
        = new ObjectWithGenericList<Car>();
    owgl.setList(l);

    JAXBContext jc = JAXBContext.newInstance(
        ObjectWithGenericList.class, Car.class);
    ObjectWithGenericList<Car> retr
        = marshallUnmarshall(owgl, jc);

    for (Car s : retr.getList()) {
        System.out.println(
        s.getClass().getSimpleName() + " - " + s.getType());
    } System.out.println(" ");

}
generates the following XML:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<objectWithGenericList>
    <MyGenericList>
        <list xsi:type="car" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
            <type>red car</type>
        </list>
        <list xsi:type="car" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
            <type>blue car</type>
        </list>
        <list xsi:type="car" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
            <type>green car</type>
        </list>
    </MyGenericList>
</objectWithGenericList>

Car - red car
Car - blue car
Car - green car
Notice that JAXB is capable of recreating Car instances.

Next

JAXB to XMLJAXB to JSONJAXB Annotations Tutorial Table Of Content

5 comments:

  1. Great info on wrapper annotation. Just trying it out now. Thank you.

    ReplyDelete
  2. Just the examples I needed in this moment, thanks for sharing the knowledge!

    ReplyDelete
  3. You keep calling marshallUnmarshall(owgl, jc) method. But I cant seem to see the implementation of this method. I understand that you may get a marshal/unmarshal from JaxbContext object. Could you kindly share your implementation. Thanks

    ReplyDelete
    Replies
    1. Hi Yousif, at the beginning of this post, I have given the link to get the source code (from git). You can get the implementation from there. Cheers!

      Delete
  4. Thanks, It's useful to me

    ReplyDelete