Este problema me ha vuelto loco: Spring es una herramienta tan potente y, sin embargo, algo tan simple como escribir una cadena de salida como JSON parece imposible sin hacks feos.
Mi solución (en Kotlin) que encuentro menos intrusiva y más transparente es usar un consejo de controlador y verificar si la solicitud fue a un conjunto particular de puntos finales (API REST normalmente, ya que a menudo queremos devolver TODAS las respuestas de aquí como JSON y no hacer especializaciones en el frontend en función de si los datos devueltos son una cadena simple ("¡No deserialización JSON!") o algo más ("¡Deserialización JSON!")). El aspecto positivo de esto es que el controlador sigue siendo el mismo y sin hacks.
El supports
método se asegura de que todas las solicitudes que fueron manejadas por StringHttpMessageConverter
(por ejemplo, el convertidor que maneja la salida de todos los controladores que devuelven cadenas simples) se procesen y en el beforeBodyWrite
método, controlamos en qué casos queremos interrumpir y convertir la salida a JSON (y modificar los encabezados en consecuencia).
@ControllerAdvice
class StringToJsonAdvice(val ob: ObjectMapper) : ResponseBodyAdvice<Any?> {
override fun supports(returnType: MethodParameter, converterType: Class<out HttpMessageConverter<*>>): Boolean =
converterType === StringHttpMessageConverter::class.java
override fun beforeBodyWrite(
body: Any?,
returnType: MethodParameter,
selectedContentType: MediaType,
selectedConverterType: Class<out HttpMessageConverter<*>>,
request: ServerHttpRequest,
response: ServerHttpResponse
): Any? {
return if (request.uri.path.contains("api")) {
response.getHeaders().contentType = MediaType.APPLICATION_JSON
ob.writeValueAsString(body)
} else body
}
}
Espero que en el futuro obtengamos una anotación simple en la que podamos anular la que HttpMessageConverter
debería usarse para la salida.