On m'a demandé d'embellir le JSON Jackson par défaut sortant d'un noeud final RestEasy. J'ai fait des recherches sur Jackson et écrit du code autonome pour pouvoir supprimer les valeurs NULL, personnaliser les formats de données, etc. Le défi consiste maintenant à injecter ce code dans la sérialisation JSON de RestEasy.
À en juger par les messages du forum, cela est trivial au printemps, mais cela ne semble pas être le cas dans RestEasy. J'ai écrit un ContextResolver et l'ai configuré en tant que resteasy.provider dans les paramètres de contexte dans web.xml (sur Tomcat), mais cela empêche le chargement de l'application Web sur Tomcat.
Maintenant, j'essaie d'étendre javax.ws.rs.core.Application et de fournir un ContextResolver sans faire de progrès. Est-ce simple, quelqu'un l'a-t-il fait? Toute aide est grandement appréciée.
Ok, j'ai compris, j'ai pu le faire en écrivant un JacksonJsonProvider personnalisé basé sur la Jackson FAQ: JAX-RS .
@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);
}
}
J'ai trouvé un moyen plus agréable de modifier Jackson SerializationConfig: vous pouvez intercepter la création d'ObjectMapper à l'aide d'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
}
Vous devrez vous inscrire à RESTEasy de l’une des manières suivantes:
Référence: RESTEasy docs
Référence: Nicklas Karlsson sur les forums JBoss
Veuillez noter que cela fonctionne avec RESTEasy 2.3.2 qui est livré comme module dans JBoss 7.1.1.Final, mais ne semble pas fonctionner avec RESTEasy 3.0-beta5.
Si vous utilisez le fournisseur Jackson2, vous devez faire quelque chose de légèrement différent de la réponse précédente. Cet exemple va joliment imprimer la sortie par défaut
@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);
}
}
et pour l'enregistrer dans votre web-xml, si vous n'avez pas d'auto-inscription, ajoutez-le à votre resteasy.providers context-param
Le fournisseur de Jackson ObjectMapper
devrait être le moyen standard JAX-RS de le faire (fonctionne avec Jersey), cela semble donc être la voie à suivre avec RESTeasy.
J'ai eu beaucoup de travail pour l'enregistrer dans mon application, même en suivant le conseil d'utiliser context-param une fois que j'utilise spring boot et que je n'ai pas web.xml.
Fournisseur personnalisé
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;
}
}
Inscription sur demande
META-INF/services/javax.ws.rs.ext.Providers
com.mageddo.CustomJacksonJsonProvider
org.jboss.resteasy.plugins.providers.jackson.UnrecognizedPropertyExceptionHandler
Si vous utilisez le fournisseur Jackson 2.2.x, Resteasy a fourni un Jolie annotation d'impression semblable à celle du fournisseur JAXB:
org.jboss.resteasy.annotations.providers.jackson.Formatted
Voici un exemple:
@GET @Produces("application/json") @Path("/formatted/{id}") @Formatted public Product getFormattedProduct() { return new Product(333, "robot"); }
Comme dans l'exemple ci-dessus, l'annotation @Formatted activera le option de Jackson sous-jacente "SerializationFeature.INDENT_OUTPUT".
© Guide de l'utilisateur RESTEasy .
Ce n'est pas une solution globale, mais vous pouvez aussi mettre l'annotation sur des classes.