users@jaxb.java.net

Rendering Collection<T> objects to JSON

From: Richard Bailey <rbailey_at_gatech.edu>
Date: Mon, 06 Apr 2009 22:02:37 -0400

Hi guys, I'm not sure if this is a bug or a misconfiguration somewhere on my part. I'm using JAXB to do object marshalling to JSON when creating a response to a REST API I'm building. I've structured each of my responses to contain an error field and a payload field.

In general everything works fine but when I want to return a list of items I'm seeing the following behavior and it feels like a bug... When I set the payload to be a converter which has a list with more than one element it's returned as an array of json encoded objects. When the list has one element though it's returning a single encoded object instead of a single element array despite the object having type Collection<T>.

I've pulled out everything from the nested coverter object for testing and and included sample output from the same below. I'd appreciate your thoughts on the matter.

Thanks
-Richard

Code:
@XmlRootElement(name = "userDevices")
public class UserDevicePayload {
    public void setDevice(List<UserDevice> l) {
        deviceList = l;
    }
    
   @XmlElement
   public Collection<UserDevice> getDevice() {
       return deviceList;
   }

   private List<UserDevice> deviceList;
}


@Provider
public final class JAXBContextResolver implements ContextResolver<JAXBContext> {

   private final JAXBContext context;

   private final Set<Class> types;

   private final Class[] cTypes = {
       WaiUsersConverter.class,
       WaiUserConverter.class,
       UriResolver.class,
       WaiUserlocationsConverter.class,
       WaiUserlocationConverter.class,
       WatchDetailsPayloadConverter.class,
       WatchDetailsPayloadConverter.class,
       ErrorConverter.class};

   public JAXBContextResolver() throws Exception {
       this.types = new HashSet(Arrays.asList(cTypes));
       this.context = new JSONJAXBContext(JSONConfiguration.mapped().rootUnwrapping(false).build(), cTypes);
   }

   public JAXBContext getContext(Class<?> objectType) {
       return (types.contains(objectType)) ? context : null;
   }
}

When the payload is a list with more than one item:
{
    "error":{"code":"","message":""},
    "payload":{
        "device":[
            {
                "description":"",
                "deviceType":"GENERIC_WIFI",
                "deviceId":"3",
                "mac":"001122334455",
                "priority":"42"
            },
            {
                "description":"",
                "deviceType":"GENERIC_WIFI",
                "deviceId":"4",
                "mac":"001122334455",
                "priority":"0"
            }
        ]
    }
}


When the payload is a list with one item:

{
    "error":{"code":"","message":""},
    "payload":{
        "device":{
            "deviceType":"LAPTOP",
            "deviceId":"1",
            "mac":"001122334455",
            "priority":"2"
        }
    }
}