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
final class JsonStringImpl implements JsonString {
private final String value;
public JsonStringImpl(String value) {
this.value = value;
}
@Override
public String getString() {
return value;
}
@Override
public CharSequence getChars() {
return value;
}
@Override
public ValueType getValueType() {
return ValueType.STRING;
}
...
}
ObjectMapper
therefore uses the Java Bean getters to serialize the JsonStringImpl
object (that is the Map Entry's value), as
{"chars":"Dade","string":"Dade","valueType":"STRING"}
The same applies for the other fields.
If you want to correctly write the JSON, simply return a String
.
@RequestMapping("/test", produces="application/json")
@ResponseBody
public String test() {
JsonObject result = Json.createObjectBuilder()
.add("name", "Dade")
.add("age", 23)
.add("married", false)
.build();
return result.toString();
}
Or make your own HandlerMethodReturnValueHandler
, a little more complicated, but more rewarding.