Question

J'utilise Jersey pour créer un service web REST pour un composant serveur.

L'objet annoté JAXB-je veux sérialisation dans une liste ressemble à ceci:

@XmlRootElement(name = "distribution")
@XmlType(name = "tDistribution", propOrder = {
    "id", "name"
})
public class XMLDistribution {
    private String id;
    private String name;
    // no-args constructor, getters, setters, etc
}

J'ai une ressource REST pour récupérer une distribution qui ressemble à ceci:

@Path("/distribution/{id: [1-9][0-9]*}")
public class RESTDistribution {
    @GET
    @Produces("application/json")
    public XMLDistribution retrieve(@PathParam("id") String id) {
        return retrieveDistribution(Long.parseLong(id));
    }
    // business logic (retrieveDistribution(long))
}

J'ai aussi une ressource REST pour récupérer une liste de toutes les distributions, qui ressemble à ceci:

@Path("/distributions")
public class RESTDistributions {
    @GET
    @Produces("application/json")
    public List<XMLDistribution> retrieveAll() {
        return retrieveDistributions();
    }
    // business logic (retrieveDistributions())
}

J'utilise un ContextResolver pour personnaliser sérialisation JAXB, qui est actuellement configuré comme ceci:

@Provider
@Produces("application/json")
public class JAXBJSONContextResolver implements ContextResolver<JAXBContext> {
    private JAXBContext context;
    public JAXBJSONContextResolver() throws Exception {
        JSONConfiguration.MappedBuilder b = JSONConfiguration.mapped();
        b.nonStrings("id");
        b.rootUnwrapping(true);
        b.arrays("distribution");
        context = new JSONJAXBContext(b.build(), XMLDistribution.class);
    }
    @Override
    public JAXBContext getContext(Class<?> objectType) {
        return context;
    }
}

Les deux fonctionnent de ressources REST, ainsi que le résolveur de contexte. Ceci est un exemple de sortie de la première:

// path: /distribution/1
{"id":1,"name":"Example Distribution"}

Ce qui est exactement ce que je veux. Ceci est un exemple de sortie pour la liste:

// path: /distributions
{"distribution":[{"id":1,"name":"Sample Distribution 1"},{"id":2,"name":"Sample Distribution 2"}]}

Ce qui est pas tout à fait ce que je veux.

Je ne comprends pas pourquoi il y a une balise distribution enfermant là. Je voulais l'enlever avec .rootUnwrapping(true) dans le résolveur contexte, mais apparemment une autre qui ne supprime que balise englobante. Ceci est la sortie avec .rootUnwrapping(false):

// path: /distribution/1
{"distribution":{"id":1,"name":"Example Distribution"}} // not ok
// path: /distributions
{"xMLDistributions":{"distribution":[{"id":1,"name":"Sample Distribution 1"},{"id":2,"name":"Sample Distribution 2"}]}}

Je devais aussi configurer .arrays("distribution") pour obtenir toujours un tableau JSON, même avec un seul élément.

Idéalement, je voudrais avoir cela comme une sortie:

// path: /distribution/1
{"id":1,"name":"Example Distribution"} // currently works
// path: /distributions
[{"id":1,"name":"Sample Distribution 1"},{"id":2,"name":"Sample Distribution 2"}]

J'ai essayé de retourner un List<XMLDistribution>, un XMLDistributionList (wrapper autour d'une liste), un XMLDistribution[], mais je ne pouvais pas trouver un moyen d'obtenir d'un simple tableau JSON des distributions dans mon format requis.

J'ai aussi essayé les autres notations retournées par JSONConfiguration.natural(), JSONConfiguration.mappedJettison(), etc, et ne pouvait pas obtenir quelque chose qui ressemble à ce que je dois.

Est-ce que quelqu'un sait s'il est possible de configurer JAXB pour le faire?

Était-ce utile?

La solution

J'ai trouvé une solution: remplacer le JAXB JSON sérialiseur avec un meilleur comportement sérialiseur JSON comme Jackson. Le plus simple est d'utiliser jackson-jaxrs, qui a déjà fait pour vous. La classe est JacksonJsonProvider. Tout ce que vous avez à faire est de modifier votre web.xml de projet afin que Jersey (ou d'une autre mise en œuvre JAX-RS) balaye pour elle. Voici ce que vous devez ajouter:

<init-param>
  <param-name>com.sun.jersey.config.property.packages</param-name>
  <param-value>your.project.packages;org.codehaus.jackson.jaxrs</param-value>
</init-param>

Et voilà tout ce qu'il ya à faire. Jackson sera utilisé pour la sérialisation JSON, et il fonctionne de la façon que vous attendez pour les listes et les tableaux.

Le plus simple est d'écrire votre propre coutume MessageBodyWriter enregistré pour produire « application / json ». Voici un exemple:

@Provider
@Produces("application/json")
public class JsonMessageBodyWriter implements MessageBodyWriter {
    @Override
    public long getSize(Object obj, Class type, Type genericType,
            Annotation[] annotations, MediaType mediaType) {
        return -1;
    }

    @Override
    public boolean isWriteable(Class type, Type genericType,
            Annotation annotations[], MediaType mediaType) {
        return true;
    }

    @Override
    public void writeTo(Object target, Class type, Type genericType,
            Annotation[] annotations, MediaType mediaType,
            MultivaluedMap httpHeaders, OutputStream outputStream)
            throws IOException {        
        new ObjectMapper().writeValue(outputStream, target);
    }
}

Vous devez vous assurer que votre web.xml comprend le paquet, comme pour la solution prête à l'emploi ci-dessus.

De toute façon: le tour est joué! Vous verrez JSON correctement formé.

Vous pouvez télécharger Jackson à partir d'ici: http://jackson.codehaus.org/

Autres conseils

La réponse de Jonhatan est grande et il a été très utile pour moi.

Juste une mise à jour:

si vous utilisez la version 2.x de Jackson (par exemple la version 2.1) est la classe com.fasterxml.jackson.jaxrs.json.JacksonJaxbJsonProvider donc le web.xml est:

<init-param>
  <param-name>com.sun.jersey.config.property.packages</param-name>
  <param-value>your.project.packages;com.fasterxml.jackson.jaxrs.json</param-value>
</init-param>
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top