4

I in my controller class a have the following method:

import javax.json.Json;
import javax.servlet.http.HttpServletRequest;
import javax.ws.rs.Consumes;
import javax.ws.rs.POST;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.core.Context;
import javax.ws.rs.core.MediaType;


@POST
@Consumes({MediaType.APPLICATION_JSON})
@Produces({MediaType.TEXT_PLAIN})
@Path("/message")
public String postMessage(Json json,
    @Context HttpServletRequest request) {
   System.out.println("message");
   return "ok";
}

The problem is when I send POST by executing curl by:

curl -H "Content-Type: application/json" -X 
POST -d '{"key":"value"}' http://localhost:8080/message

I get HTTP Status 415 - Unsupported Media Type as if I didn't send JSON. When I change Json json, to String body the controller works fine.

In web.xml I have:

<servlet>
        <servlet-name>jersey-serlvet</servlet-name>
        <servlet-class>org.glassfish.jersey.servlet.ServletContainer</servlet-class>
        <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>

EDIT

I had wrong JSON as suggested in the comments. However, even with a correct one like {"key":"value"} the code won't work.

menteith
  • 596
  • 14
  • 51

3 Answers3

1

As far as I know jersey uses jackson's ObjectMapper to deserialize stuff. I think the problem may be that object mapper dont know how to map your request to javax.json.Json object, a simple test:

import javax.json.Json;
import com.fasterxml.jackson.databind.ObjectMapper;
// (...)
ObjectMapper mapper = new ObjectMapper();
Json json = mapper.readValue("{\"key\": \"value\"}", Json.class);

This produces an exception:

UnrecognizedPropertyException: Unrecognized field "key" (class javax.json.Json)

I think you should create a POJO instead of raw json objects, for example:

class MyMessage {
  public String key; //for simplicity, you probably will use accessor methods
}

And the same test works fine:

MyMessage msg = mapper.readValue("{\"key\": \"value\"}", MyMessage.class);

and then your controller method should look like this:

@POST
@Consumes({MediaType.APPLICATION_JSON})
@Produces({MediaType.TEXT_PLAIN})
@Path("/message")
public String postMessage(MyMessage msg) {
  System.out.println(msg.key);
  return "ok";
}
Michal Lonski
  • 877
  • 1
  • 11
  • 20
  • You were right about object mapper not knowing how to map. I had missing dependencies and I [solved it](https://stackoverflow.com/a/46406070/2657875). Now `MyMessage msg = mapper.readValue("{\"key\": \"value\"}", MyMessage.class); ` works great. However, I still get an error `Unsupported Media Type`. I'm using your controller. – menteith Mar 26 '18 at 13:46
1

I solved the problem. In a class that extends ResourceConfig there has to be register(JacksonFeature.class) instruction, e.g.:

public class ApplicationConfig extends ResourceConfig {

    public ApplicationConfig() {
        super(MyController.class);

        property(CommonProperties.FEATURE_AUTO_DISCOVERY_DISABLE, true);
        register(JacksonFeature.class);
    }
}
menteith
  • 596
  • 14
  • 51
0

Make sure that you have an implementation of MessageBodyReader in your classpath, that could consume JSON

Community
  • 1
  • 1
Nikolai Shevchenko
  • 7,083
  • 8
  • 33
  • 42