users@jersey.java.net

Re: [Jersey] 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: Jakub Podlesak <Jakub.Podlesak_at_Sun.COM>
Date: Mon, 20 Jul 2009 14:06:27 +0200

Hi Ian,

On Fri, Jul 17, 2009 at 02:51:06PM -0400, Stevens, Ian wrote:
> 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

You needed concrete List implementation, as JAXB refused to play
with the interface List, right?

> 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

Where did you read that? I presume it is part of JAXB docs?

> 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?

I am sorry, but IMHO using the JAXB->JSON way, you will not be able to get what you want.
You might want to use the low-level JSON approach [1] for generating the JSON,
or Tatu's Java->JSON provider [2].

~Jakub


[1]https://jersey.dev.java.net/documentation/1.1.1-ea/user-guide.html#d4e645
[2]http://www.cowtowncoder.com/blog/archives/2009/03/entry_229.html

>
> 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.