users@jersey.java.net

How do I marshal nested lists as JSON? I get an array of nulls or an array of one-element dictionaries containing an array.

From: Stevens, Ian <IStevens_at_globeandmail.com>
Date: Fri, 17 Jul 2009 14:51:06 -0400

I'm working on a project which uses Jersey to convert objects to JSON.
I'd like to be able to write out nested lists, like so:
 
    {"data":[["one", "two", "three"], ["a", "b", "c"]]}
 
The object I'd like to convert first represented data as a
<LinkedList<LinkedList<String>>>, and I figured Jersey would just do the
right thing. The above was output as a list of nulls:
 
    {"data":[null, null]}
 
After reading that nested objects need to be wrapped, I tried the
following:
 
@XmlRootElement(name = "foo")
@XmlType(propOrder = {"data"})
public class Foo
{
    private Collection<FooData> data = new LinkedList<FooData>();
 
    @XmlElement(name = "data")
    public Collection<FooData> getData()
    {
        return data;
    }
 
    public void addData(Collection data)
    {
        FooData d = new FooData();
        for(Object o: data)
        {
            d.getData().add(o == null ? (String)o : o.toString());
        }
        this.data.add(d);
    }
 
    @XmlRootElement(name = "FooData")
    public static class FooData
    {
        private Collection<String> data = new LinkedList<String>();
 
        @XmlElement
        public Collection<String> getData()
        {
            return data;
        }
    }
}
 
That code outputs what's below, which is closer to what I want:
 
    {"data":[{"data":["one", "two", "three"]},{"data":["a", "b", "c"]}]}
 
I want the first data to be a list of lists, not a list of one-element
dictionaries. How do I achieve this?
 
Here's my JAXBContentResolver:
 
@Provider
public class JAXBContextResolver implements ContextResolver<JAXBContext>
{
    private JAXBContext context;
    private Set<Class<?>> types;
 
    // Only parent classes are required here. Nested classes are
implicit.
    protected Class<?>[] classTypes = new Class[] {Foo.class};
 
    protected Set<String> jsonArray = new HashSet<String>(1) {
        {
            add("data");
        }
    };
 
    public JAXBContextResolver() throws Exception
    {
        Map<String, Object> props = new HashMap<String, Object>();
        props.put(JSONJAXBContext.JSON_NOTATION,
JSONJAXBContext.JSONNotation.MAPPED);
        props.put(JSONJAXBContext.JSON_ROOT_UNWRAPPING, Boolean.TRUE);
        props.put(JSONJAXBContext.JSON_ARRAYS, jsonArray);
        this.types = new HashSet<Class<?>>(Arrays.asList(classTypes));
        this.context = new JSONJAXBContext(classTyes, props);
    }
    
    public JAXBContext getContext(Class<?> objectType)
    {
        return (types.contains(objectType)) ? context : null;
    }
}

thanks,
Ian.