Comment réutiliser le JSON/JAXB De Jersey pour la sérialisation?

j'ai un service de repos JAX-RS implémenté en utilisant Jersey. Une des caractéristiques cool de JAX-RS/Jersey est la facilité avec laquelle un POJO peut être transformé en un service de repos, simplement en saupoudrant quelques annotations Java... incluant un mécanisme trivialement facile pour traduire les POJOs en JSON-en utilisant les annotations JAXB.

maintenant, je voudrais pouvoir profiter de cette fonctionnalité de JSON-ifying cool pour des buts non-REST - j'aimerais être en mesure de sérialiser certains de ces objets sur le disque, comme JSON text. Voici un exemple d'objet JAXB que je voudrais sérialiser:

@XmlRootElement(name = "user")
public class UserInfoImpl implements UserInfo {

    public UserInfoImpl() {} 

    public UserInfoImpl(String user, String details) {
        this.user = user;
        this.details = details;
    }

    public String getUser() { return user; }
    public void setUser(String user) { this.user = user; }

    public String getDetails() { return details; }
    public void setDetails(String details) { this.details = details; }

    private String user;
    private String details;
}

Jersey peut transformer l'un d'eux en json sans aucune information supplémentaire. Je me demande si Jersey a exposé cette fonctionnalité dans L'API pour des besoins comme le mien? Je n'ai pas réussi à le trouver jusqu'à présent...

Merci!

mise à jour 2009-07-09: j'ai appris que je peux utiliser les Fournisseurs de l'objet presque faire exactement ce que je veux:

  @Context Providers ps;
  MessageBodyWriter uw = ps.getMessageBodyWriter(UserInfoImpl.class, UserInfoImpl.class, new Annotation[0], MediaType.APPLICATION_JSON_TYPE);

  uw.writeTo(....)

... Ceci écrit l'objet comme json à n'importe quel outputstream, ce qui serait parfait pour moi, mais je ne peux obtenir l'objet Providers qu'en utilisant @Context à partir d'un objet @Component. Est-ce que quelqu'un sait comment y accéder à partir d'un POJO régulier et non annoté? Merci!

28
demandé sur ctwomey 2009-07-02 03:03:05

7 réponses

Jersey utilise un couple de cadres différents selon que vous utilisez mapped(), badgerfish(), ou natural() notation. Naturel est généralement celui que les gens veulent. Et c'est mis en œuvre en utilisant le Très bon (et très rapide) processeur autonome Jackson JSON, je crois, qui va de L'objet->JAXB->JSON. Cependant Jackson fournit également son propre fournisseur JAX-RS pour aller objet direct - > JSON.

en fait, ils ont même ajouté le support pour les annotations JAXB. Avoir un coup d'oeil

http://wiki.fasterxml.com/JacksonJAXBAnnotations

je pense que c'est finalement ce que vous cherchez. Jackson ne objet < ->JSON processing...Jersey fait juste les appels pour vous

19
répondu Andy O 2009-11-06 23:05:56

voici un bref exemple simple d'utilisation de JAXB pour mapper des objets vers JSON (en utilisant Jackson):

http://ondra.zizka.cz/stranky/programovani/java/jaxb-json-jackson-howto.texy

6
répondu Ondra Žižka 2009-11-22 15:46:44
ObjectMapper mapper = new ObjectMapper();
String str = mapper.writeValueAsString(pojoObject);
5
répondu RimasK 2011-11-02 10:49:31

les annotations JAXB fonctionnent bien lors de la sérialisation vers XML. Le problème principal est que JAXB ne supporte pas les tableaux vides. Donc quand on sérialise quelque chose comme ça...

List myArray = new ArrayList();

...en json via jaxb anottations tous vos tableaux vides devenir null au lieu de [].

pour résoudre ceci vous pouvez sérialiser vos pojos directement à json via jackson.

jetez un oeil à ceci de L'utilisateur de Jersey guide: http://jersey.java.net/nonav/documentation/latest/user-guide.html#d0e1959

C'est la meilleure façon d'utiliser Jackson provider sans JAXB. De plus, vous pouvez toujours utiliser la dernière version de jackson en downlaoding jackson-all-X. Y. z-jar de sa toile.

cette méthode ne va pas interférer avec vos annotations jaxb donc je suggère d'essayer!

3
répondu ramon_salla 2010-11-17 14:39:37

depuis Jersey est une mise en œuvre de référence de JAX-RS et JAX-RS est entièrement axé sur la fourniture d'une façon standard de mettre en œuvre le point final pour le service de repos, les questions de sérialisation de la charge utile est laissée à d'autres normes.

je pense que si ils inclus sérialisation d'un objet dans le JAX-RS standard, il devient rapidement un grand multi-tête de la bête qui serait difficile à mettre en œuvre et de perdre un peu de son orientation.

j'apprécie à quel point Jersey est sur la livraison propre et simple d'utiliser des points de repos. Dans mon cas, j'ai juste sous-classé un parent qui a toute la plomberie JAXB dedans donc le fait de regrouper des objets entre binaire et XML est très propre.

1
répondu Jack Cox 2009-07-09 17:27:40

avec un bootstrapping spécifique au petit Jersey, vous pouvez l'utiliser pour créer les objets JSON nécessaires pour vous. Vous devez inclure les dépendances suivantes (vous pouvez utiliser le paquet, mais cela va causer des problèmes si vous êtes à l'aide de Soudure pour le test):

    <dependency>
        <groupId>com.sun.jersey</groupId>
        <artifactId>jersey-json</artifactId>
        <version>1.12</version>
    </dependency>
    <dependency>
        <groupId>com.sun.jersey</groupId>
        <artifactId>jersey-client</artifactId>
        <version>1.12</version>
    </dependency>

A partir de là, vous pouvez créer une classe annotée JAXB. Voici un exemple:

@XmlRootElement
public class TextMessage {
private String text;
    public String getText() { return text; }
    public void setText(String s) { this.text = text; }
}

alors vous pouvez créer le test d'unité suivant:

    TextMessage textMessage = new TextMessage();
    textMessage.setText("hello");
    textMessage.setUuid(UUID.randomUUID());

    // Jersey specific start
    final Providers ps = new Client().getProviders();
    // Jersey specific end
    final MultivaluedMap<String, Object> responseHeaders = new MultivaluedMap<String, Object>() {

        @Override
        public void add(final String key, final Object value) {
        }

        @Override
        public void clear() {
        }

        @Override
        public boolean containsKey(final Object key) {
            return false;
        }

        @Override
        public boolean containsValue(final Object value) {
            return false;
        }

        @Override
        public Set<java.util.Map.Entry<String, List<Object>>> entrySet() {
            return null;
        }

        @Override
        public List<Object> get(final Object key) {
            return null;
        }

        @Override
        public Object getFirst(final String key) {
            return null;
        }

        @Override
        public boolean isEmpty() {
            return false;
        }

        @Override
        public Set<String> keySet() {
            return null;
        }

        @Override
        public List<Object> put(final String key, final List<Object> value) {
            return null;
        }

        @Override
        public void putAll(
                final Map<? extends String, ? extends List<Object>> m) {
        }

        @Override
        public void putSingle(final String key, final Object value) {
        }

        @Override
        public List<Object> remove(final Object key) {
            return null;
        }

        @Override
        public int size() {
            return 0;
        }

        @Override
        public Collection<List<Object>> values() {
            return null;
        }
    };

    final MessageBodyWriter<TextMessage> messageBodyWriter = ps
            .getMessageBodyWriter(TextMessage.class, TextMessage.class,
                    new Annotation[0], MediaType.APPLICATION_JSON_TYPE);
    final ByteArrayOutputStream baos = new ByteArrayOutputStream();
    Assert.assertNotNull(messageBodyWriter);

    messageBodyWriter.writeTo(textMessage, TextMessage.class,
            TextMessage.class, new Annotation[0],
            MediaType.APPLICATION_JSON_TYPE, responseHeaders, baos);
    final String jsonString = new String(baos.toByteArray());
    Assert.assertTrue(jsonString.contains("\"text\":\"hello\""));

L'avantage de cette approche est qu'il garde tout dans L'API JEE6, aucune bibliothèque externe n'est explicitement nécessaire sauf pour tester et obtenir les fournisseurs. Cependant, vous devez créer une implémentation de MultivaluedMap car il n'y a rien dans la norme et nous ne l'utilisons pas réellement. aussi être plus lent que GSON, et beaucoup plus compliqué que nécessaire.

1
répondu Archimedes Trajano 2012-05-30 12:47:50

je comprends les vues XML mais il aurait montré une certaine prévoyance pour exiger le soutien de JSON POJOs comme équipement standard. Il n'y a pas de sens à recoder les identificateurs JSON avec des caractères spéciaux si votre implémentation est JSON et votre client est un RIA JavaScript.

en outre, pas que les haricots Java ne sont pas des POJOs. Je voudrais utiliser quelque chose comme ceci sur la surface extérieure de mon niveau web:

public class Model
{
   @Property height;
   @Property weight;
   @Property age;
}

pas de constructeur par défaut, Pas de bruit getter/ setter, juste un POJO avec mes propres annotations.

0
répondu Jason Plank 2011-11-21 20:50:17