Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Jersey response for empty list is null instead of {}

Tags:

rest

jersey

I have a JAX-RS REST service using Jersey. I use JAXB for JSON marshalling (ie. @XmlRootElement) One of the method returns a list of objects persisted with JPA.

When this list contains entries it works as I expect. Example:

{"androidDevice":[{"email":"[email protected]","timeCreated":"2012-10-19T
22:41:26.862+02:00"},{"email":"[email protected]","timeCreated":"2012-10-
19T22:41:38.093+02:00"}]}

However, if the list is empty (or null) I would expect it to return {}.

Instead it returns null. Example:

$ curl  -i -H "Accept: application/json" http://....
HTTP/1.1 200 OK
Content-Type: application/json

null

Here is the code

    @GET
@Produces( { MediaType.APPLICATION_JSON ,  MediaType.APPLICATION_XML})
public List<AndroidDevice> getAndroidDevices() {
    logger.info("getAndroidDevices method called");


    EntityManager entityManager = entityMangerFactory.createEntityManager();  
    List<AndroidDevice> resultList = entityManager.createNamedQuery(AndroidDevice.QUERY_ALL_ENTRIES,  
            AndroidDevice.class).getResultList();  

    //avoid returning content null. (doesn't work)
    if(resultList==null){
        resultList=new ArrayList<AndroidDevice>();
    }

    return resultList;
}

Is there any way to get Jersey to return an empty JSON list (besides hardcoding a ResponseBuilder) ?

Should I instead provide a different response code for such events?

Update: Got a tips through twitter about this bug report which concludes with that they won't fix it http://java.net/jira/browse/JERSEY-339

Update2: In addition to the solution below, since I was using an Application for configuration (refered to in web.xml), I had to manually add the Provider class there. Here is the relevant code.

public class JAXRSApplication extends Application {

    @Override
    public Set<Class<?>> getClasses() {
        Set<Class<?>> set = new HashSet<Class<?>>();
        //Add all endpoints to this set
        set.add(AndroidDeviceEndpoint.class);
        //Add Providers
        set.add(JAXBContextResolver.class);
        return set;
    }   
}
like image 639
dparnas Avatar asked Feb 19 '23 18:02

dparnas


1 Answers

To achieve more important JSON format changes, you will need to configure Jersey JSON procesor itself. Various configuration options could be set on an JSONConfiguration instance. The instance could be then further used to create a JSONConfigurated JSONJAXBContext, which serves as a main configuration point in this area. To pass your specialized JSONJAXBContext to Jersey, you will finally need to implement a JAXBContext ContextResolver:

@Provider
public class JAXBContextResolver implements ContextResolver<JAXBContext> {
    private final JAXBContext context;
    private final Set<Class> types;
    private Class[] ctypes = { AndroidDevice.class}; //your pojo class
    public JAXBContextResolver() throws Exception {
        this.types = new HashSet(Arrays.asList(ctypes));
        this.context = new JSONJAXBContext(JSONConfiguration.natural().build(),
                ctypes); //json configuration
    }

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

refer to jersey official document for detailed information.

like image 171
secondflying Avatar answered Feb 26 '23 23:02

secondflying