Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
290 views
in Technique[技术] by (71.8m points)

java - Returning JsonObject using @ResponseBody in SpringMVC

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:

@RequestMapping("/test")
@ResponseBody
public JsonObject test() {
        JsonObject result = Json.createObjectBuilder()
                .add("name", "Dade")
                .add("age", 23)
                .add("married", false)
                .build();
        return result;
    }

And when I access this, instead of getting the expected representation of the JSON, I get these instead:

{"name":{"chars":"Dade","string":"Dade","valueType":"STRING"},"age":{"valueType":"NUMBER","integral":true},"married":{"valueType":"FALSE"}}

Why is this? What is going on? And how do I make it returned the expected JSON properly?

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

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.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...