Tuesday, September 25, 2012

Custom JAXBContextResolver


JSON representation for single record element which is declared as a java array or a collection, using jersey would display it as a single element rather than JSON array.

For example:


For single record:

"employee":
         {
           "id": "16",
           "name": "Sunil"
         }

Where as it is expected to display it as:

"employee":
      [ 
         {
           "id": "16",
           "name": "Sunil"
         }
      ]



If you need to handle JSON produced by Jersey for a single element collection, then we need to customize the JAXBContext Resolver. A provider class annotated with @provider needs to extend the ContextResolver of javax.ws.rs.ext package.


/**
 * This helps in configuring the JSON output format.
 */
@Provider
public class JAXBContextResolver extends ContextResolver {

    /**
     * The JAXBContext object.
     */
    private JAXBContext context;
    /**
     * The class types.
     */
    private final Class[] types = {Employee.class};

    /**
     * Constructs the JSON output format for the specified class types.
     *
     * @throws Exception the exception
     */
    public JAXBContextResolver() throws Exception {
        this.context = new JSONJAXBContext(JSONConfiguration.mapped().arrays("employee").build(), types);
    }

    /**
     * Returns the current context for the given class.
     *     
     * @param objectType the JAXBContext for the given class object.
     * @return the JAXBContext.
     */
    @Override
    public JAXBContext getContext(final Class objectType) {
        for (Class type : types) {
            if (type == objectType) {
                return context;
            }
        }
        return null;
    }
}


In the above class, the Employee.java is a simple Java Bean class which has 'employee' attribute which is a Java arrays or a collection. If that element contains multiple values then JSON conversion would be displayed:

For single record:


"employee":
      [ 
         {
           "id": "16",
           "name": "Sunil"
         }
      ]

  For Multiple Records

  "employee":
       [
           {
               "id": "16",
               "name": "Sunil"
           },
           {
               "id": "17",
               "name": "Ajeesh"
           },
           {
               "id": "18",
               "name": "Sanjay"
           }
       ]



One issue with this implementation is one need to maintain the affected classes/items manually in their implementation. So, you need to add as many as classes that have Java collection to the above class and get the configuration 'mapped' to JSON array.


private final Class[] types = {Employee.class, Company.class};

and

this.context = new JSONJAXBContext(JSONConfiguration.mapped().arrays("employee", "company").build(), types);

2 comments:

  1. Thank you for post. Really Helpful

    ReplyDelete
  2. hi i am trying to implement this but i am getting ContextResolver cannot be resolved to a type also at compile time i am getting to remove @Override from
    public JAXBContext getContext(final Class objectType) {

    ReplyDelete