web-dev-qa-db-fra.com

Accéder à Jackson Object Mapper dans RestEasy

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.

25
codegeek

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);
    }
}
15
codegeek

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:

  • Renvoyez-le en tant que classe ou instance à partir d'une implémentation javax.ws.rs.core.Application
  • Répertoriez-le en tant que fournisseur avec resteasy.providers
  • Laissez RESTEasy le rechercher automatiquement dans votre fichier WAR. Voir le guide de configuration
  • Ajoutez-le manuellement via ResteasyProviderFactory.getInstance (). RegisterProvider (Class) ou registerProviderInstance (Object)

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.

14
James Baxter

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

2
Tadhg

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.

2
StaxMan

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
1
deFreitas

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.

0