Tenho um RestController de amostra no Spring Boot:
@RestController
@RequestMapping("/api")
class MyRestController
{
@GetMapping(path = "/hello")
public JSONObject sayHello()
{
return new JSONObject("{'aa':'bb'}");
}
}
Estou usando a biblioteca JSON org.json
Quando eu clico na API /hello
, recebo uma exceção dizendo:
Servlet.service () para servlet [dispatcherServlet] no contexto com o caminho [] lançou a exceção [Falha no processamento da solicitação; a exceção aninhada é java.lang.IllegalArgumentException: Nenhum conversor encontrado para o valor de retorno do tipo: class org.json.JSONObject] com causa raiz
java.lang.IllegalArgumentException: Nenhum conversor encontrado para o valor de retorno do tipo: class org.json.JSONObject
Qual é o problema? Alguém pode explicar o que exatamente está acontecendo?
java
json
spring-boot
response
Iwekesi
fonte
fonte
@GetMapping(path = "/hello") @ResponseBody public String sayHello() {return"{'aa':'bb'}";}
Respostas:
Como você está usando a Web do Spring Boot, a dependência de Jackson está implícita e não precisamos definir explicitamente. Você pode verificar a dependência de Jackson em seu
pom.xml
na guia de hierarquia de dependência se estiver usando o eclipse.E, como você anotou,
@RestController
não há necessidade de fazer uma conversão json explícita. Basta retornar um POJO e o serializador jackson cuidará da conversão para json. É equivalente a usar@ResponseBody
quando usado com @Controller. Em vez de colocar@ResponseBody
em cada método de controlador, colocamos em@RestController
vez de vanilla@Controller
e,@ResponseBody
por padrão, é aplicado em todos os recursos nesse controlador.Consulte este link: https://docs.spring.io/spring/docs/current/spring-framework-reference/html/mvc.html#mvc-ann-responsebody
O problema que você está enfrentando é porque o objeto retornado (JSONObject) não tem getter para certas propriedades. E sua intenção não é serializar este JSONObject, mas sim serializar um POJO. Então é só devolver o POJO.
Consulte este link: https://stackoverflow.com/a/35822500/5039001
Se você deseja retornar uma string serializada json, basta retornar a string. O Spring usará StringHttpMessageConverter em vez do conversor JSON neste caso.
fonte
Map<String,Object>
ou umProperties
objetoA razão pela qual sua abordagem atual não funciona é porque Jackson é usado por padrão para serializar e desserializar objetos. No entanto, ele não sabe como serializar o
JSONObject
. Se você deseja criar uma estrutura JSON dinâmica, pode usar umMap
, por exemplo:@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; }
Isso levará à seguinte resposta JSON:
{ "key": "value", "foo": "bar", "aa": "bb" }
Isso é um pouco limitado, pois pode se tornar um pouco mais difícil adicionar objetos filhos. Jackson tem seu próprio mecanismo, porém, usando
ObjectNode
eArrayNode
. Para usá-lo, você deve fazer o autowireObjectMapper
em seu serviço / controlador. Então você pode usar:@GetMapping public ObjectNode sayHello() { ObjectNode objectNode = mapper.createObjectNode(); objectNode.put("key", "value"); objectNode.put("foo", "bar"); objectNode.put("number", 42); return objectNode; }
Essa abordagem permite adicionar objetos filho, matrizes e usar todos os vários tipos.
fonte
ObjectMapper
você deve autowire (veja o parágrafo acima do meu último trecho de código).java.util.HashMap
é uma funcionalidade central do Java desde o Java 1.2.Você pode retornar uma resposta conforme
String
sugerido por @vagaasen ou pode usar oResponseEntity
objeto fornecido pelo Spring conforme abaixo. Desta forma, você também pode retornar oHttp status code
que é mais útil na chamada de serviço da web.@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); } }
fonte
JSONObject
, mas como o Spring usa Jackson, mudei para umHashMap
e então o código que li nesta resposta funcionou.você também pode usar um hashmap para isso
@GetMapping public HashMap<String, Object> get() { HashMap<String, Object> map = new HashMap<>(); map.put("key1", "value1"); map.put("results", somePOJO); return map; }
fonte
@RequestMapping("/api/status") public Map doSomething() { return Collections.singletonMap("status", myService.doSomething()); }
PS. Funciona apenas para 1 valor
fonte
usar
ResponseEntity<ResponseBean>
Aqui você pode usar ResponseBean ou Any java bean conforme desejar para retornar sua resposta de API e essa é a melhor prática. Usei Enum como resposta. ele retornará o código de status e a mensagem de status da API.
@GetMapping(path = "/login") public ResponseEntity<ServiceStatus> restApiExample(HttpServletRequest request, HttpServletResponse response) { String username = request.getParameter("username"); String password = request.getParameter("password"); loginService.login(username, password, request); return new ResponseEntity<ServiceStatus>(ServiceStatus.LOGIN_SUCCESS, HttpStatus.ACCEPTED); }
para resposta ServiceStatus ou (ResponseBody)
public enum ServiceStatus { LOGIN_SUCCESS(0, "Login success"), private final int id; private final String message; //Enum constructor ServiceStatus(int id, String message) { this.id = id; this.message = message; } public int getId() { return id; } public String getMessage() { return message; } }
Spring REST API deve ter a chave abaixo na resposta
você receberá a resposta final abaixo
{ "StatusCode" : "0", "Message":"Login success" }
você pode usar ResponseBody (java POJO, ENUM, etc.) de acordo com sua necessidade.
fonte
Criação mais correta de DTO para consultas de API, por exemplo, entityDTO:
Mas se você precisar retornar diferentes parâmetros de mapa, pode usar os próximos dois exemplos
2. Para retornar um parâmetro como mapa:
fonte
Se você precisar retornar um objeto JSON usando uma String, o seguinte deve funcionar:
import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.ObjectMapper; import org.springframework.http.ResponseEntity; ... @RestController @RequestMapping("/student") public class StudentController { @GetMapping @RequestMapping("/") public ResponseEntity<JsonNode> get() throws JsonProcessingException { ObjectMapper mapper = new ObjectMapper(); JsonNode json = mapper.readTree("{\"id\": \"132\", \"name\": \"Alice\"}"); return ResponseEntity.ok(json); } ... }
fonte