Возврат объекта JSON в качестве ответа в Spring Загрузка
У меня есть образец RestController в Spring Boot:
@RestController
@RequestMapping("/api")
class MyRestController
{
@GetMapping(path = "/hello")
public JSONObject sayHello()
{
return new JSONObject("{'aa':'bb'}");
}
}
Я использую библиотеку JSON org.json
Когда я нажимаю API /hello
, я получаю исключение, говорящее:
Servlet.service() для сервлета [dispatcherServlet] в контексте с путем [] вызвала исключение [Ошибка обработки запроса; Вложенное исключение - java.lang.IllegalArgumentException: не найдено преобразователя для возвращаемого значения типа: class org.json.JSONObject] с первопричиной.
java.lang.IllegalArgumentException: не найдено преобразователя для возвращаемого значения типа: класс org.json.JSONObject
В чем проблема? Может кто-нибудь объяснить, что именно происходит?
Ответы
Ответ 1
Поскольку вы используете Spring Boot web, зависимость Джексона является неявной, и нам не нужно определять ее явно. Вы можете проверить зависимость Джексона в вашем pom.xml
на вкладке иерархии зависимостей, если используете eclipse.
И поскольку вы аннотировали @RestController
не нужно делать явное преобразование json. Просто верните POJO, и сериализатор Джексона позаботится о преобразовании в json. Это эквивалентно использованию @ResponseBody
при использовании с @Controller. Вместо того, чтобы помещать @ResponseBody
на каждый метод контроллера, мы @RestController
вместо vanilla @Controller
и @ResponseBody
по умолчанию применяется ко всем ресурсам в этом контроллере.
Перейдите по этой ссылке: https://docs.spring.io/spring/docs/current/spring-framework-reference/html/mvc.html#mvc-ann-responsebody
Проблема, с которой вы сталкиваетесь, заключается в том, что возвращаемый объект (JSONObject) не имеет метода получения для определенных свойств. И вы намерены не сериализовать этот JSONObject, а вместо этого сериализовать POJO. Так что просто верните POJO.
Перейдите по этой ссылке: fooobar.com/questions/144648/...
Если вы хотите вернуть сериализованную строку json, просто верните строку. В этом случае Spring будет использовать StringHttpMessageConverter вместо JSON-конвертера.
Ответ 2
Причина, по которой ваш текущий подход не работает, заключается в том, что Джексон по умолчанию используется для сериализации и десериализации объектов. Однако он не знает, как сериализовать JSONObject
. Если вы хотите создать динамическую структуру JSON, вы можете использовать Map
, например:
@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;
}
Это приведет к следующему ответу JSON:
{ "key": "value", "foo": "bar", "aa": "bb" }
Это немного ограничено, так как может быть немного сложнее добавить дочерние объекты. У Джексона есть свой механизм, используя ObjectNode
и ArrayNode
. Чтобы использовать его, вы должны autwire ObjectMapper
в вашем сервисе/контроллере. Затем вы можете использовать:
@GetMapping
public ObjectNode sayHello() {
ObjectNode objectNode = mapper.createObjectNode();
objectNode.put("key", "value");
objectNode.put("foo", "bar");
objectNode.put("number", 42);
return objectNode;
}
Этот подход позволяет вам добавлять дочерние объекты, массивы и использовать все различные типы.
Ответ 3
Вы можете либо вернуть ответ в виде String
как предложено @vagaasen, либо использовать объект ResponseEntity
предоставленный Spring, как показано ниже. Таким образом, вы также можете вернуть Http status code
который более полезен при вызове веб-сервиса.
@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);
}
}
Ответ 4
вы также можете использовать hashmap для этого
@GetMapping
public HashMap<String, Object> get() {
HashMap<String, Object> map = new HashMap<>();
map.put("key1", "value1");
map.put("results", somePOJO);
return map;
}
Ответ 5
@RequestMapping("/api/status")
public Map doSomething()
{
return Collections.singletonMap("status", myService.doSomething());
}
PS. Работает только для 1 значения