When accessing a web server or application, every HTTP request that is received by a server is responded to with an HTTP status code. HTTP status codes are three-digit codes, and are grouped into five different classes. The class of a status code can be quickly identified by its first digit: 1xx. That means that if our service just calls this method and returns directly to the controller, we’ll get an HTTP code 200 (OK) even if the resource isn’t found. In fact, the proper approach is to return a HTTP code 404 (NOT FOUND) as specified in the HTTP/1.1 spec.
I am using the new Java API (JSR 353) for JSON in a SpringMVC project.
The idea is to generate some piece of Json data and have it returned to the client. The controller I have look somewhat like this:
And when I access this, instead of getting the expected representation of the JSON, I get these instead:
Why is this? What is going on? And how do I make it returned the expected JSON properly?
2 Answers
The answer is pretty simple when you realize there is no special HandlerMethodReturnValueHandler
for the new JSR 353 API. Instead, in this case, the RequestResponseBodyMethodProcessor
(for @ResponseBody
) uses a MappingJackson2HttpMessageConverter
to serialize the return value of your handler method.
Internally, the MappingJackson2HttpMessageConverter
uses an ObjectMapper
. By default, the ObjectMapper
uses the getters of a class to serialize an object to JSON.
Assuming you are using Glassfish
's provider implementation of the JSR 353, those classes are org.glassfish.json.JsonObjectBuilderImpl$JsonObjectImpl
, org.glassfish.json.JsonStringImpl
, and org.glassfish.json.JsonNumberImpl
, and javax.json.JsonValue$3
(an anonymous class for the value FALSE
).
Because JsonObjectImpl
(your result, ie. root, object) is a Map
(special type), ObjectMapper
serializes the map's entries as JSON key-value pair elements, where the Map key is the JSON key, and the Map value is the JSON value. For the key, it works fine, serializing as name
, age
, and married
. For the value, it uses the classes I mentioned above and their respective getters. For example, org.glassfish.json.JsonStringImpl
is implemented as
ObjectMapper
therefore uses the Java Bean getters to serialize the JsonStringImpl
object (that is the Map Entry's value), as
The same applies for the other fields.
If you want to correctly write the JSON, simply return a String
.
Or make your own HandlerMethodReturnValueHandler
, a little more complicated, but more rewarding.
The answer from Sotirios Delimanolis does indeed work, but in my case I had to ensure the proper HttpMessageConverter order was in place. This is because I needed to also convert JodaTime values to ISO 8601 format. This custom WebMvcConfigurerAdapter Configuration worked for me: