How do I marshal java.util.List with JAXB like JAX-RS (CXF, and Jersey) do [duplicate]
Question
This question already has an answer here:
It seems the latest JAX-RS can handle methods returning java.util.List as the XMLRootElement but normal JAXB cannot. I would like to mimic what CXF and Jersey are doing.
In other words I would like to Marshal a List and just like CXF and Jersey do. Normally if you try to marshal a list with JAXB you get the Root Element exception. How do I get around this with out having to make a wrapping object?
EDIT: Thanks for the many answers but I'm very familiar with the @XmlElementWrapper but that does not even come close to simulating what JAX-RS is doing.
JAX-RS does this:
@XmlRootElement(name="dog")
public class Dog {
private String name;
public String getName() { return this.name; }
//Setter also
}
Now if I serialize a list of dogs:
serialize(List<Dog> dogs);
XML should be (what JAX-RS does):
<dogs>
<dog><name>Rascal</name></dog>
</dogs>
So you can see I don't want to have to make a wrapper object for every single domain object.
Solution 7
Blaise Doughan I believe shows a good solution for this problem here: Is it possible to programmatically configure JAXB?
and
http://blog.bdoughan.com/2012/11/creating-generic-list-wrapper-in-jaxb.html
and somewhat here albeit slightly different use case:
http://blog.bdoughan.com/2012/02/xmlanyelement-and-xmladapter.html
OTHER TIPS
Could you not simply add:
@XmlElementWrapper(name = "wrapperName")
No need to make a wrapper object. This will then be the route element in your marshalled XML response.
I used a custom iterable list using the following code, hope this helps.
package bindings;
import java.io.Serializable;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlElementWrapper;
import javax.xml.bind.annotation.XmlRootElement;
import javax.xml.bind.annotation.XmlType;
@XmlType
@XmlRootElement
public class CustomBindList<V> implements Iterable<V>, Serializable {
private static final long serialVersionUID = 4449835205581297830L;
@XmlElementWrapper(name = "List")
@XmlElement(name = "Entry")
private final List<V> list = new LinkedList<V>();
public CustomBindList() {
}
public void add(final V obj) {
list.add(obj);
}
public V get(final int index) {
return list.get(index);
}
@Override
public Iterator<V> iterator() {
return list.iterator();
}
public int size() {
return list.size();
}
}
I have a secret which allows me to avoid screwing with JAXB mappings entirely and have everything work magically.
Have used this approach for years, never spent even 5 minutes worrying about marshalling/unmarshalling. The secret is.... don't use JAXB. :)
In most of my projects which use JAX-RS, I configure Jersey to use xstream and let xstream figure out how to marshal/unmarshal for me. (or jackson for JSON)
Maybe there are some reasons to use JAXB instead of something like xstream/jackson, but I haven't found any yet.
mapping a List can be done like this..
@XmlAccessorType(XmlAccessType.FIELD)
@XmlType
public class TestRootObject {
@XmlElement(name = "testList")
private List<TestObj> testList;
//getter setter
}
check Jackson out, it is very compatible with JAXB bindings and using MappingJsonFactory you can actually interchangeably use Java to XML to Java to Json to Java.
I annotate my collections with @XmlJavaTypeAdapter(value = Adapter.class)
.
The Adapter class extends from XmlAdapter<key, value>
the key is a unique identifier to (un)marshal and the value is your domain object.
Maybe this can help you out. However you do have to create an adapter for every domain object.