2

Like in trying-to-use-spring-boot-rest-to-read-json-string-from-post I want to read a json payload from a POST request in a Spring RestController. Using the content type "text/plain" there is no problem, but with "application/json" the deserialization fails and I get a MessageNotReadable exception. But actually the content couldn't be simpler, it is just an empty json object "{}". Could it be that a required converter is missing? I use Spring Root version 1.2.3.RELEASE.

Coding Example

@RequestMapping(value = "/deepdefinitions", method = POST, headers = "Accept=application/json")
@ResponseBody
public Definitions createOrUpdateDefinitions(HttpEntity<String> httpEntity) throws IOException { ... }

Curl Call

curl -H  "Content-type: application/json" -X POST -d '{}' http://localhost:8080/deepdefinitions

Error

{"timestamp":1434397457853,"status":400,"error":"Bad Request","exception":"org.springframework.http.converter.HttpMessageNotReadableException","message":"Could not read JSON: Can not deserialize instance of java.lang.String out of START_OBJECT token\n at [Source: org.apache.catalina.connector.CoyoteInputStream@122f9ce3; line: 1, column: 1]; nested exception is com.fasterxml.jackson.databind.JsonMappingException: Can not deserialize instance of java.lang.String out of START_OBJECT token\n at [Source: org.apache.catalina.connector.CoyoteInputStream@122f9ce3; line: 1, column: 1]","path":"/deepdefinitions"}
Community
  • 1
  • 1
Gregor
  • 2,917
  • 5
  • 28
  • 50
  • 1
    You should use headers = "Accept=application/json" in '@RequestMapping' and pass the serialized object in '@RequestBody' to your controller method – Darshan Jun 15 '15 at 12:00
  • Show the exact exception/stack trace please. – ci_ Jun 15 '15 at 13:03
  • @Darshan, the "headers" in RequestMapping does not change the behaviour. I update the question with a coding example. – Gregor Jun 15 '15 at 19:46

1 Answers1

2

From Spring REST guide:

The Accept and Content-Type HTTP headers can be used to describe the content being sent or requested within an HTTP request. The client may set Accept to application/json if it is requesting a response in JSON. Conversely, when sending data, setting the Content-Type to application/xml tells the client that the data being sent in the request is XML.

It appears your Controller is processing only Accept header:

@RequestMapping(value = "/deepdefinitions", method = POST, headers = "Accept=application/json")

You need to change it to:

@RequestMapping(value = "/deepdefinitions", method = POST, headers = "Accept=application/json, Content-type=application/json")

There are also consumes and produces elements available in @RequestMapping annotation.

The Spring MVC documentation recommends:

Although you can match to Content-Type and Accept header values using media type wild cards (for example "content-type=text/*" will match to "text/plain" and "text/html"), it is recommended to use the consumes and produces conditions respectively instead. They are intended specifically for that purpose.


Going by your related post, you should change your method signature to:

@ResponseBody
public Definitions createOrUpdateDefinitions(@RequestBody String value, HttpEntity<String> httpEntity) throws IOException

I think you should also change you curl command as below. This is because {}(JavaScript Object literal) would map to a object and to map to a String you should use a empty string '' literal.

curl -H "Content-type: application/json" -X POST -d '' http://localhost:8080/deepdefinitions
informatik01
  • 16,038
  • 10
  • 74
  • 104
randominstanceOfLivingThing
  • 16,873
  • 13
  • 49
  • 72
  • I had used the consumes condition before. It was Darsham who recommended to use the accept header. But the consumes leads to the same problem. – Gregor Jun 16 '15 at 03:50