Tengo un RestController de muestra en Spring Boot:
@RestController
@RequestMapping("/api")
class MyRestController
{
@GetMapping(path = "/hello")
public JSONObject sayHello()
{
return new JSONObject("{'aa':'bb'}");
}
}
Estoy usando la biblioteca JSON org.json
Cuando presiono API /hello
, obtengo una excepción que dice:
Servlet.service () para servlet [dispatcherServlet] en contexto con la ruta [] arrojó una excepción [El procesamiento de la solicitud falló; La excepción anidada es java.lang.IllegalArgumentException: No se encontró un convertidor para el valor de retorno del tipo: class org.json.JSONObject] con la causa raíz.
java.lang.IllegalArgumentException: No se encontró ningún convertidor para el valor de retorno del tipo: class org.json.JSONObject
¿Cual es el problema? ¿Alguien puede explicar qué está sucediendo exactamente?
java
json
spring-boot
response
iwekesi
fuente
fuente
@GetMapping(path = "/hello") @ResponseBody public String sayHello() {return"{'aa':'bb'}";}
Respuestas:
Como está utilizando la web Spring Boot, la dependencia de Jackson es implícita y no tenemos que definirla explícitamente. Puede verificar la dependencia de Jackson en su
pom.xml
en la pestaña de jerarquía de dependencia si usa eclipse.Y como ha anotado,
@RestController
no es necesario realizar una conversión json explícita. Simplemente devuelva un POJO y el serializador jackson se encargará de convertir a json. Es equivalente a usar@ResponseBody
cuando se usa con @Controller. En lugar de colocar@ResponseBody
en cada método de controlador, colocamos en lugar@RestController
de vainilla@Controller
y,@ResponseBody
de forma predeterminada, se aplica a todos los recursos en ese controlador.Consulte este enlace: https://docs.spring.io/spring/docs/current/spring-framework-reference/html/mvc.html#mvc-ann-responsebody
El problema al que se enfrenta es porque el objeto devuelto (JSONObject) no tiene getter para ciertas propiedades. Y su intención no es serializar este JSONObject, sino serializar un POJO. Así que devuelve el POJO.
Consulte este enlace: https://stackoverflow.com/a/35822500/5039001
Si desea devolver una cadena serializada json, simplemente devuelva la cadena. Spring usará StringHttpMessageConverter en lugar del convertidor JSON en este caso.
fuente
Map<String,Object>
unProperties
objeto o un objetoLa razón por la que su enfoque actual no funciona es porque Jackson se usa de forma predeterminada para serializar y deserializar objetos. Sin embargo, no sabe cómo serializar
JSONObject
. Si desea crear una estructura JSON dinámica, puede usarMap
, por ejemplo:@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; }
Esto conducirá a la siguiente respuesta JSON:
{ "key": "value", "foo": "bar", "aa": "bb" }
Esto es un poco limitado, ya que puede resultar un poco más difícil agregar objetos secundarios. Sin embargo, Jackson tiene su propio mecanismo, usando
ObjectNode
yArrayNode
. Para usarlo, debe realizar un autowireObjectMapper
en su servicio / controlador. Entonces puedes usar:@GetMapping public ObjectNode sayHello() { ObjectNode objectNode = mapper.createObjectNode(); objectNode.put("key", "value"); objectNode.put("foo", "bar"); objectNode.put("number", 42); return objectNode; }
Este enfoque le permite agregar objetos secundarios, matrices y usar todos los tipos.
fuente
ObjectMapper
que debe conectar automáticamente (consulte el párrafo anterior a mi último fragmento de código).java.util.HashMap
es una funcionalidad central de Java desde Java 1.2.Puede devolver una respuesta como
String
lo sugiere @vagaasen o puede usar elResponseEntity
Objeto proporcionado por Spring como se muestra a continuación. De esta manera, también puede devolver loHttp status code
que es más útil en la llamada de servicio 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); } }
fuente
JSONObject
, pero como Spring usa Jackson, lo cambié a aHashMap
y luego el código que leí en esta respuesta funcionó.también puedes usar un mapa de hash para esto
@GetMapping public HashMap<String, Object> get() { HashMap<String, Object> map = new HashMap<>(); map.put("key1", "value1"); map.put("results", somePOJO); return map; }
fuente
@RequestMapping("/api/status") public Map doSomething() { return Collections.singletonMap("status", myService.doSomething()); }
PD. Funciona solo por 1 valor
fuente
utilizar
ResponseEntity<ResponseBean>
Aquí puede usar ResponseBean o Any Java Bean como desee para devolver su respuesta de API y es la mejor práctica. He usado Enum como respuesta. devolverá el código de estado y el mensaje de estado de la 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 respuesta ServiceStatus o (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 debe tener la siguiente clave en respuesta
obtendrá la respuesta final a continuación
{ "StatusCode" : "0", "Message":"Login success" }
puede utilizar ResponseBody (java POJO, ENUM, etc.) según sus necesidades.
fuente
Más correcto crear DTO para consultas de API, por ejemplo entityDTO:
Pero si necesita devolver diferentes parámetros de Map, puede usar los dos ejemplos siguientes
2. Para devolver un parámetro como map:
fuente
Si necesita devolver un objeto JSON usando una cadena, lo siguiente debería 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); } ... }
fuente