Reputation: 3301
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?
Upvotes: 1
Views: 4320
Reputation: 29266
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);
}
Upvotes: 0
Reputation: 279880
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);
Upvotes: 3