简体   繁体   中英

Why does Spring MVC report “No converter found for return value of type: class org.json.JSONObject”?

I want to return a JSON made of two strings and don't know how to implement it. Here is my code:

 @PostMapping
public ResponseEntity<> createUser(@RequestBody User user ) {

    JSONObject responseJson = new JSONObject();

    if (userService.userExists(user)) {

        responseJson.put("status", "User with that username already exists.");

        return new ResponseEntity<>(responseJson, HttpStatus.BAD_REQUEST);
    }

    responseJson.put("status", "User created.");

    return new ResponseEntity<>(responseJson, HttpStatus.CREATED);
}

I've got Json » 20160810 and com.fasterxml.jackson.core in my pom.xml and I'm still getting java.lang.IllegalArgumentException: No converter found for return value of type: class org.json.JSONObject Why doesn't Jackson automatically converts my JSON? It's a standard one, just simple key:value. Maybe there is better way to create simple JSONs using some class in jackson.core so I don't have to inlude Json lib in my project and jackson automatically converts them?

I don't know why you're using two JSON parsing libraries. Instead of creating a JSONObject , create Jackson's equivalent ObjectNode .

Assuming you have access to the ObjectMapper used by your Spring MVC stack

@Autowired
private ObjectMapper objectMapper;

use it to create and populate the ObjectNode

ObjectNode jsonObject = mapper.createObjectNode();
jsonObject.put("status", "User with that username already exists.");
// don't forget to change return type to support this
return new ResponseEntity<>(jsonObject, HttpStatus.BAD_REQUEST);

Since this is a Jackson type, Jackson knows how to serialize it.

It doesn't know how to serialize JSONObject . Some of the following explanation comes from my answer here .

Essentially, Spring MVC uses HandlerMethodReturnValueHandler implementations to handle values returned by @RequestMapping ( @PostMapping ) annotated methods. For ResponseEntity , that implementation is HttpEntityMethodProcessor .

This implementation simply loops through a collection of HttpMessageConverter instances, checks if an instance can serialize the body of the ResponseEntity , and uses it if it can.

Unfortunately, Jackson's HttpMessageConverter implementation, MappingJackson2HttpMessageConverter , uses an ObjectMapper to serialize these objects and ObjectMapper cannot serialize JSONObject because it can't discover any properties in the class (ie. bean getters).

Jackson's HttpMessageConverter can't do it and neither can all the other ones that are registered by default. That's why Spring MVC reports "no converter".

org.springframework.web.util.NestedServletException: Request processing failed; nested exception is java.lang.IllegalArgumentException: No converter found for return value of type: class org.json.JSONObject

An alternative solution is to serialize the JSONObject yourself to a String and pass that to the ResponseEntity . Obviously you'll want to change your return type to support String . In this case, Spring MVC will use a StringHttpMessageConverter . However, you'll want to specify the application/json content type yourself because it doesn't add it. For example,

HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_JSON);
return new ResponseEntity<>(responseJson.toString(), headers, HttpStatus.BAD_REQUEST);

Jackson does not know about org.json.JSONObject , use JsonNode instead for key/value pair.

Update after comment:

Could you write me an example how would you use it? I find it a bit confusing

@PostMapping
public ResponseEntity<JsonNode> createUser(@RequestBody User user) {
        ObjectMapper objectMapper = new ObjectMapper();

        Map<String, String> responseJson = new HashMap<>();
        if (userService.userExists(user)) {
            responseJson.put("status",
                    "User with that username already exists.");
            JsonNode jsonNode = objectMapper.valueToTree(responseJson);
            return new ResponseEntity<JsonNode>(jsonNode,
                    HttpStatus.BAD_REQUEST);
        }
        responseJson.put("status", "User created.");
        JsonNode jsonNode = objectMapper.valueToTree(responseJson);
        return new ResponseEntity<>(jsonNode, HttpStatus.CREATED);
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM