Returning JSON object as response in Spring Boot
Solution 1
As you are using Spring Boot web, Jackson dependency is implicit and we do not have to define explicitly. You can check for Jackson dependency in your pom.xml
in the dependency hierarchy tab if using eclipse.
And as you have annotated with @RestController
there is no need to do explicit json conversion. Just return a POJO and jackson serializer will take care of converting to json. It is equivalent to using @ResponseBody
when used with @Controller. Rather than placing @ResponseBody
on every controller method we place @RestController
instead of vanilla @Controller
and @ResponseBody
by default is applied on all resources in that controller.
Refer this link: https://docs.spring.io/spring/docs/current/spring-framework-reference/html/mvc.html#mvc-ann-responsebody
The problem you are facing is because the returned object(JSONObject) does not have getter for certain properties. And your intention is not to serialize this JSONObject but instead to serialize a POJO. So just return the POJO.
Refer this link: https://stackoverflow.com/a/35822500/5039001
If you want to return a json serialized string then just return the string. Spring will use StringHttpMessageConverter instead of JSON converter in this case.
Solution 2
The reason why your current approach doesn't work is because Jackson is used by default to serialize and to deserialize objects. However, it doesn't know how to serialize the JSONObject
. If you want to create a dynamic JSON structure, you can use a Map
, for example:
@GetMapping
public Map<String, String> sayHello() {
HashMap<String, String> map = new HashMap<>();
map.put("key", "value");
map.put("foo", "bar");
map.put("aa", "bb");
return map;
}
This will lead to the following JSON response:
{ "key": "value", "foo": "bar", "aa": "bb" }
This is a bit limited, since it may become a bit more difficult to add child objects. Jackson has its own mechanism though, using ObjectNode
and ArrayNode
. To use it, you have to autowire ObjectMapper
in your service/controller. Then you can use:
@GetMapping
public ObjectNode sayHello() {
ObjectNode objectNode = mapper.createObjectNode();
objectNode.put("key", "value");
objectNode.put("foo", "bar");
objectNode.put("number", 42);
return objectNode;
}
This approach allows you to add child objects, arrays, and use all various types.
Solution 3
You can either return a response as String
as suggested by @vagaasen or you can use ResponseEntity
Object provided by Spring as below. By this way you can also return Http status code
which is more helpful in webservice call.
@RestController
@RequestMapping("/api")
public class MyRestController
{
@GetMapping(path = "/hello", produces=MediaType.APPLICATION_JSON_VALUE)
public ResponseEntity<Object> sayHello()
{
//Get data from service layer into entityList.
List<JSONObject> entities = new ArrayList<JSONObject>();
for (Entity n : entityList) {
JSONObject entity = new JSONObject();
entity.put("aa", "bb");
entities.add(entity);
}
return new ResponseEntity<Object>(entities, HttpStatus.OK);
}
}
Solution 4
you can also use a hashmap for this
@GetMapping
public Map<String, Object> get() {
Map<String, Object> map = new HashMap<>();
map.put("key1", "value1");
map.put("results", somePOJO);
return map;
}
Solution 5
More correct create DTO for API queries, for example entityDTO:
- Default response OK with list of entities:
@GetMapping(produces=MediaType.APPLICATION_JSON_VALUE) @ResponseStatus(HttpStatus.OK) public List<EntityDto> getAll() { return entityService.getAllEntities(); }
But if you need return different Map parameters you can use next two examples
2. For return one parameter like map:
@GetMapping(produces=MediaType.APPLICATION_JSON_VALUE) public ResponseEntity<Object> getOneParameterMap() { return ResponseEntity.status(HttpStatus.CREATED).body( Collections.singletonMap("key", "value")); }
- And if you need return map of some parameters(since Java 9):
@GetMapping(produces = MediaType.APPLICATION_JSON_VALUE) public ResponseEntity<Object> getSomeParameters() { return ResponseEntity.status(HttpStatus.OK).body(Map.of( "key-1", "value-1", "key-2", "value-2", "key-3", "value-3")); }
![iwekesi](https://i.stack.imgur.com/UEjVK.jpg?s=256&g=1)
iwekesi
Updated on February 20, 2022Comments
-
iwekesi over 2 years
I have a sample RestController in Spring Boot:
@RestController @RequestMapping("/api") class MyRestController { @GetMapping(path = "/hello") public JSONObject sayHello() { return new JSONObject("{'aa':'bb'}"); } }
I am using the JSON library
org.json
When I hit API
/hello
, I get an exception saying :Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception [Request processing failed; nested exception is java.lang.IllegalArgumentException: No converter found for return value of type: class org.json.JSONObject] with root cause
java.lang.IllegalArgumentException: No converter found for return value of type: class org.json.JSONObject
What is the issue? Can someone explain what exactly is happening?
-
iwekesi about 7 yearswhat is mapper here?
-
g00glen00b about 7 years@iwekesi that's the Jackson
ObjectMapper
you should autowire (see the paragraph above my last code snippet). -
iwekesi about 7 yearsIf I add JSONObject in entities, it is again giving me similar exception
-
prem kumar about 7 yearsif json string is what you want to return from java then you can just return a string if it is already json serialized. No need to convert string to json and json back to string.
-
Vihung almost 7 yearsIf you want to return a set of name-value pairs without a rigid compile-time structure, you could return a
Map<String,Object>
or aProperties
object -
divine over 6 years@Sangam your answer helped me for another problem related to jackson-dataformat-xml
-
jones-chris over 6 yearsThis was a big help! Thank you!
-
Orkun Ozen over 6 years@prem kumar random question : what do you mean with 'instead of vanilla Controller and ResponseBody'? what s vanilla here?
-
prem kumar over 6 yearsi meant a usual Controller and with ResponseBody annotation placed on every request method.
-
Melvin Roest almost 6 yearsI wonder why this answer isn't upvoted more. I'm new to Spring too, so I don't know if this is a good software engineering practice. With that said, this answer really helped me. However, I did have a lot of trouble with a
JSONObject
, but since Spring uses Jackson I changed it to aHashMap
instead and then the code that I read in this answer did work. -
Sandeep Mandori almost 6 years+1 for suggesting the MediaType.APPLICATION_JSON_VALUE as it ensures that produced result get parsed as json not xml as may happen if you don't define
-
xmlParser over 5 yearsWhere did you declare your entityList?
-
Sangam Belose over 5 years@xmlParser its assumed to be received from service layer. Here we dont do any IDE validation whether you have declared the list and all those things. Its considered by default.Please read the question carefully. Understand the question carefully before downvoting.
-
xmlParser over 5 years@SangamBelose nvm I have done it manually... Changed the vote too.
-
cogitoergosum over 4 yearsIt is stunning to know that one has to go such lengths for producing meaningful JSON objects! It is also sad that Pivotal makes no effort at all (spring.io/guides/gs/actuator-service) to call out these limitations. Luckily, we have SO! ;)
-
sak over 3 yearsit is returning this for me: [ { "empty": false } ]
-
Sangam Belose over 3 years@sak you need to read the data into entityList from some source.
-
sak over 3 yearswhat source? can you please name any?
-
Sangam Belose over 3 years@sak The source can be anything, may be service layer getting data from database or any file storage.
-
Mahmoud Magdy over 2 yearswhere mapper come from sorry I'm beginner and i tried this code nothing name mapper
-
g00glen00b over 2 years@MahmoudMagdy It's an
ObjectMapper
. If you use Spring boot with Spring web, you can autowire it in any other Spring bean. -
Cletus Ajibade over 2 yearsIn addition to what @premkumar said, you can check out this reference link docs.spring.io/spring-boot/docs/current/reference/htmlsingle/…, Spring MVC uses the HttpMessageConverter interface to convert HTTP requests and responses using the Jackson library by default.