How do I marshal java.util.List with JAXB like JAX-RS (CXF, and Jersey) do [duplicate]

StackOverflow https://stackoverflow.com/questions/2827788

  •  26-09-2019
  •  | 
  •  

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.

Was it helpful?

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.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top