我在SpringMVC项目中将新的Java API(JSR 353)用于JSON。
这个想法是生成一些Json数据并将其返回给客户端。我所拥有的控制器看起来像这样:
@RequestMapping("/test") @ResponseBody public JsonObject test() { JsonObject result = Json.createObjectBuilder() .add("name", "Dade") .add("age", 23) .add("married", false) .build(); return result; }
当我访问它时,我没有得到JSON的预期表示,而是得到了这些:
{"name":{"chars":"Dade","string":"Dade","valueType":"STRING"},"age":{"valueType":"NUMBER","integral":true},"married":{"valueType":"FALSE"}}
为什么是这样?到底是怎么回事?以及如何使它正确返回预期的JSON?
当您意识到HandlerMethodReturnValueHandler新的JSR 353 API 没有特殊要求时,答案很简单。相反,在这种情况下,RequestResponseBodyMethodProcessor(for @ResponseBody)使用MappingJackson2HttpMessageConverter来序列化处理程序方法的返回值。
HandlerMethodReturnValueHandler
RequestResponseBodyMethodProcessor
@ResponseBody
MappingJackson2HttpMessageConverter
在内部,MappingJackson2HttpMessageConverter使用ObjectMapper。默认情况下,ObjectMapper使用类的getter将对象序列化为JSON。
ObjectMapper
假设你正在使用Glassfish的该JSR 353的提供者实现,这些类是org.glassfish.json.JsonObjectBuilderImpl$JsonObjectImpl,org.glassfish.json.JsonStringImpl和 org.glassfish.json.JsonNumberImpl,和javax.json.JsonValue$3(该值的匿名类FALSE)。
Glassfish
org.glassfish.json.JsonObjectBuilderImpl$JsonObjectImpl
org.glassfish.json.JsonStringImpl
org.glassfish.json.JsonNumberImpl
javax.json.JsonValue$3
FALSE
因为JsonObjectImpl(您的结果(即根,对象))是Map(特殊类型),ObjectMapper所以将地图的条目序列化为JSON键值对元素,其中Map键是JSON键,而Map值是JSON值。对于关键的,它工作正常,如序列化name,age和married。对于值,它使用我上面提到的类及其各自的getter。例如,org.glassfish.json.JsonStringImpl实现为
JsonObjectImpl
Map
name
age
married
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因此,使用Java Bean getter来序列化JsonStringImpl对象(即Map Entry的值),如下所示:
JsonStringImpl
{"chars":"Dade","string":"Dade","valueType":"STRING"}
其他字段也一样。
如果要正确编写JSON,只需返回String。
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(); }
或者自己制作HandlerMethodReturnValueHandler,稍微复杂一点,但会带来更多回报。