在SpringMVC中使用@ResponseBody返回JsonObject

时间:2013-10-06 00:16:06

标签: java json spring-mvc

我在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?

2 个答案:

答案 0 :(得分:24)

当您意识到新的JSR 353 API没有特殊的HandlerMethodReturnValueHandler时,答案非常简单。相反,在这种情况下,RequestResponseBodyMethodProcessor(对于@ResponseBody)使用MappingJackson2HttpMessageConverter来序列化处理程序方法的返回值。

在内部,MappingJackson2HttpMessageConverter使用ObjectMapper。默认情况下,ObjectMapper使用类的getter将对象序列化为JSON。

假设您正在使用JSR 353的Glassfish提供程序实现,那些类是org.glassfish.json.JsonObjectBuilderImpl$JsonObjectImplorg.glassfish.json.JsonStringImplorg.glassfish.json.JsonNumberImpljavax.json.JsonValue$3(值为FALSE的匿名类)。

因为JsonObjectImpl(您的结果,即根,对象)是Map(特殊类型),ObjectMapper将地图的条目序列化为JSON键值对元素,其中Map键是JSON键,Map值是JSON值。对于密钥,它可以正常工作,序列化为nameagemarried。对于该值,它使用我上面提到的类和它们各自的getter。例如,org.glassfish.json.JsonStringImpl实现为

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的值),如

{"chars":"Dade","string":"Dade","valueType":"STRING"}

这同样适用于其他领域。

如果要正确编写JSON,只需返回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,更复杂,但更有价值。

答案 1 :(得分:1)

Sotirios Delimanolis的答案确实有效,但在我的情况下,我必须确保正确的HttpMessageConverter订单到位。这是因为我还需要将JodaTime值转换为ISO 8601格式。这个自定义WebMvcConfigurerAdapter配置对我有用:

function detect(elem, rettext=false){
var answer=[];
//loop trough childs
for(i=0;i<elem.childNodes.length;i++){
  e=elem.childNodes[i];
  if(e.nodeType==3&&rettext){
      //elems child is direct x child+text so lets add it
      answer.push(e.textContent);
  }else{
  //elems child is an element so lets loop trough
  if( (" " + e.className + " ").replace(/[\n\t]/g, " ").indexOf(" x ") > -1 ){
       //e is x so lets get direct childs and create one string
 answer.push(detect(e,true).join(""));
     }else{
     //not x so lets loop trough and return array

     a=detect(e);
     for(b=0;b<a.length;b++){
     answer.push(a[b]);
     }
     }
     }
     }
     return answer;
  }



 //start if window loaded
  window.onload=()=>{
  theansweris=detect(document.body);
  }