6

I'm using JAX-RS + Jersey to consume the web-service request and Jackson to translate JSON data:

@Path("/")
public class JAXRSRestController {
    @Path("/jsonRequest")
    @POST
    @Consumes(MediaType.APPLICATION_JSON)
    public Response submitJsonRequest(SampleObject sampleObject, @Context HttpHeaders headers)
    {
        Ack ack = new Ack();
        ack.setUniqueId(sampleObject.getId());
        ack.setType(sampleObject.getName());
        return Response.ok().entity(ack).build();
    }
}

Here if the request is in the below format, it would not be consumed:

{
  "sampleObject": {
    "id": "12345",
    "name": "somename"
  }
}

But if the request is in the below format, it will be consumed:

{
    "id": "12345",
    "name": "somename"
}

How can I make the controller consume the Json root element as well?

SampleObject class:

import org.codehaus.jackson.map.annotate.JsonRootName;

@XmlRootElement(name = "sampleObject")
@JsonRootName(value = "sampleObject")
@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(name  = "SampleObject", propOrder = {
        "id",
        "name"
})
public class SampleObject 
{
    protected String id;
    protected String name;

    public SampleObject(){}

    public SampleObject(String id, String name) {
        this.id = id;
        this.name = name;
    }
    public String getId() {
        return id;
    }
    public void setId(String id) {
        this.id = id;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
}

web.xml:

<?xml version="1.0" encoding= "UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" >
  <display-name>Wed Application</display-name>
  <servlet>
    <servlet-name>Jersey RESTFul WebSerivce</servlet-name>
    <servlet-class>com.sun.jersey.spi.container.servlet.ServletContainer</servlet-class>
    <init-param>
        <param-name>com.sun.jersey.config.property.packages</param-name>
        <param-value>com.jaxrs.rest</param-value>
    </init-param>
    <init-param>
        <param-name>com.sun.jersey.api.json.POJOMappingFeature</param-name>
        <param-value>true</param-value>
    </init-param>
    <load-on-startup>1</load-on-startup>
  </servlet>
  <servlet-mapping>
    <servlet-name>Jersey RESTFul WebSerivce</servlet-name>
    <url-pattern>/*</url-pattern>
  </servlet-mapping>
</web-app>
ᄂ ᄀ
  • 5,669
  • 6
  • 43
  • 57
Nishanth
  • 317
  • 4
  • 16
  • The answer (http://stackoverflow.com/questions/16380065/how-to-extract-objectmapper-from-jax-rs-client/16384686#16384686) provided for this question works on jetty server, but when I deploy it on the WAS (Websphere Application Sever 8.0) it does not work. The mapper in the constructor loads when the application starts, but when the json request comes to the controller it does not get the mapper from the getContext in the ObjectMapperContextResolver class to wrap the root element. – Nishanth Feb 19 '15 at 20:20

1 Answers1

6

There are two approaches I can think of. If this is a common occurrence in your application, I would recommend enabling unwrapping on your ObjectMapper. If this is a one-off situation, a wrapper object is not a bad option.

A. Enable Unwrapping

@JsonRootName will only apply if unwrapping is enabled on the ObjectMapper. You can accomplish this with a deserialization feature. Note that this will unwrap all requests:

public CustomObjectMapper() {
   super();
   enable(DeserializationFeature.UNWRAP_ROOT_VALUE);
}

If you do not already have a custom ObjectMapper registered then you will need to add a provider to register your custom config with Jersey. This answer explains how do accomplish that.

B. Create a Wrapper

If you do not want to unwrap globally, you can create a simple wrapper object and omit the @JsonRootName annotation:

public class SampleObjectWrapper {
   public SampleObject sampleObject;
}

Then update your resource method signature to accept the wrapper:

public Response submitJsonRequest(SampleObjectWrapper sampleObjectWrapper, @Context HttpHeaders headers)
Community
  • 1
  • 1
Sam Berry
  • 7,394
  • 6
  • 40
  • 58
  • How can we invoke the CustomObjectMapper to enable UNWRAP_ROOT_VALUE of the DeserializationFeature, when the request hits the post method using the context root. – Nishanth Jan 31 '15 at 16:55
  • 1
    Take a look at [this answer](http://stackoverflow.com/a/16384686/1756430), if this works for you let me know and I will expand on my answer to include creating the provider. There is also some quality information there about how Jersey invokes an `ObjectMapper`. Creating a `CustomObjectMapper` is just a way to abstract the mapper's configuration from the provider code. – Sam Berry Jan 31 '15 at 17:12
  • Thank You Sam. It worked. [This Answer worked](http://stackoverflow.com/questions/16380065/how-to-extract-objectmapper-from-jax-rs-client/16384686#16384686). It will do both unwrap and wrap for json requests and responses. – Nishanth Jan 31 '15 at 18:30
  • Great! I have updated my answer to include the link. – Sam Berry Jan 31 '15 at 18:44
  • The answer (http://stackoverflow.com/questions/16380065/how-to-extract-objectmapper-from-jax-rs-client/16384686#16384686) provided for this question works on jetty server, but when I deploy it on the WAS (Websphere Application Sever 8.0) it does not work. The mapper in the constructor loads when the application starts, but when the json request comes to the controller it does not get the mapper from the getContext in the ObjectMapperContextResolver class to wrap the root element. – Nishanth Feb 19 '15 at 20:27
  • 1
    While using jersey 2.0 container (org.glassfish.jersey.servlet.ServletContainer). Need to configure the jackson mapper this way (https://www.nabisoft.com/tutorials/java-ee/producing-and-consuming-json-or-xml-in-java-rest-services-with-jersey-and-jackson) – Nishanth Oct 02 '15 at 15:58