json - unknown - Accediendo a Jackson Object Mapper en RestEasy
objectmapper configure deserializationfeature fail_on_unknown_properties false); (6)
Se me ha pedido que embellezca por defecto a Jackson JSON que sale de un punto final RestEasy. Investigué un poco sobre Jackson y escribí un código independiente para poder suprimir nulos, personalizar formatos de datos, etc. Ahora el desafío es inyectar este código en la serialización JSON de RestEasy.
A juzgar por las publicaciones del foro, esto es trivial en Spring, sin embargo, no parece ser el caso en RestEasy. Escribí un ContextResolver y lo configuré como resteasy.provider en contexto params en web.xml (en Tomcat) pero eso impide que la aplicación web se cargue en Tomcat.
Ahora estoy tratando de extender javax.ws.rs.core.Application y proporcionar un ContextResolver pero sin hacer ningún progreso. ¿Es esto sencillo, alguien lo ha hecho? Cualquier ayuda es muy apreciada.
Si está utilizando el proveedor Jackson 2.2.x, Resteasy ha proporcionado una nota de impresión bastante similar a la del proveedor de JAXB:
org.jboss.resteasy.annotations.providers.jackson.Formatted
Aquí hay un ejemplo:
@GET @Produces("application/json") @Path("/formatted/{id}") @Formatted public Product getFormattedProduct() { return new Product(333, "robot"); }
Como se muestra en el ejemplo anterior, la anotación @Formatted habilitará la opción subyacente de Jackson "SerializationFeature.INDENT_OUTPUT".
Esta no es una solución global, pero también puede poner la anotación en las clases.
El proveedor de Jackson ObjectMapper
debería ser la forma estándar de JAX-RS de hacer esto (funciona con Jersey), por lo que parece ser el camino a seguir con RESTeasy también.
Encontré una forma más agradable de modificar el Jackson SerializationConfig: puede interceptar la creación de ObjectMapper utilizando un ContextResolver JAX-RS.
@Provider
@Produces(Array(MediaType.APPLICATION_JSON))
class JacksonConfig extends ContextResolver[ObjectMapper] {
val mapper = new ObjectMapper()
mapper.getSerializationConfig.setSerializationInclusion(Inclusion.NON_NULL)
def getContext(objectType: Class[_]) = mapper
}
Deberá registrarse en RESTEasy de una de las siguientes maneras:
- Devuélvalo como una clase o instancia desde una implementación javax.ws.rs.core.Application
- Listar como proveedor con resteasy.providers
- Deje que RESTEasy lo busque automáticamente en su archivo WAR. Ver guía de configuración
- Añádalo manualmente a través de ResteasyProviderFactory.getInstance (). RegisterProvider (Class) o registerProviderInstance (Object)
Referencia: documentos RESTEasy
Referencia: Nicklas Karlsson en los foros de JBoss.
Tenga en cuenta que esto funciona con RESTEasy 2.3.2, que se envía como un módulo en JBoss 7.1.1.Final, pero no parece funcionar con RESTEasy 3.0-beta5.
Ok, lo descubrí, pude hacerlo escribiendo un JacksonJsonProvider personalizado basado en las preguntas frecuentes de Jackson: JAX-RS . El código es el siguiente:
@Provider
public class QBOJacksonJsonProvider extends JacksonJsonProvider {
public static final String DATE_FORMAT = "yyyy-MM-dd HH:mm:ss";
@Override
public void writeTo(Object value, Class<?> type, Type genericType, Annotation[] annotations, MediaType mediaType, MultivaluedMap<String,Object> httpHeaders, OutputStream entityStream) throws IOException, WebApplicationException {
Log.info(getClass(), "In custom JSON provider");
//get the Object Mapper
ObjectMapper mapper = locateMapper(type, mediaType);
// Suppress null properties in JSON output
mapper.getSerializationConfig().setSerializationInclusion(org.codehaus.jackson.map.annotate.JsonSerialize.Inclusion.NON_NULL);
// Set human readable date format
SimpleDateFormat sdf = new SimpleDateFormat(DATE_FORMAT);
mapper.getSerializationConfig().setDateFormat(sdf);
super.writeTo(value, type, genericType, annotations, mediaType, httpHeaders, entityStream);
}
}
Si está utilizando el proveedor Jackson2, debe hacer algo ligeramente diferente a la respuesta anterior. Este ejemplo imprimirá la salida por defecto.
@Provider
public class JSONProvider extends ResteasyJackson2Provider {
@Override
public void writeTo(Object value, Class<?> type, Type genericType, Annotation[] annotations, MediaType json, MultivaluedMap<String, Object> headers, OutputStream body) throws IOException {
ObjectMapper mapper = locateMapper(type, json);
mapper.enable(SerializationFeature.INDENT_OUTPUT);
super.writeTo(value, type, genericType, annotations, json, headers, body);
}
}
y para registrarlo en su web-xml, si no tiene activado el registro automático, agréguelo a resteasy.providers context-param
Tuve mucho trabajo para registrarlo en mi aplicación, incluso siguiendo la sugerencia de usar context-param una vez que esté usando Spring Boot y no tenga web.xml, aquí está lo que hice.
Proveedor personalizado
package com.mageddo;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.jboss.resteasy.plugins.providers.jackson.ResteasyJackson2Provider;
import javax.ws.rs.Consumes;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.ext.Provider;
@Provider
@Consumes({"application/json", "application/*+json", "text/json"})
@Produces({"application/json", "application/*+json", "text/json"})
public class CustomJacksonJsonProvider extends ResteasyJackson2Provider {
private ObjectMapper objectMapper = new ObjectMapper(); // my own object mapper
@Override
public ObjectMapper locateMapper(Class<?> type, MediaType mediaType) {
return objectMapper;
}
}
Registro en la aplicación
META-INF / services / javax.ws.rs.ext.Providers
com.mageddo.CustomJacksonJsonProvider
org.jboss.resteasy.plugins.providers.jackson.UnrecognizedPropertyExceptionHandler