web-dev-qa-db-fra.com

Comment utiliser le support Jersey JSON POJO?

J'ai un objet que j'aimerais utiliser dans JSON en tant que ressource RESTful. Le support JSON POJO de Jersey est activé comme suit (dans le fichier web.xml):

<servlet>  
    <servlet-name>Jersey Web Application</servlet-name>  
    <servlet-class>com.Sun.jersey.spi.container.servlet.ServletContainer</servlet-class>
    <init-param>
        <param-name>com.Sun.jersey.api.json.POJOMappingFeature</param-name>
        <param-value>true</param-value>
    </init-param>

    <load-on-startup>1</load-on-startup>  
</servlet>  

Mais lorsque j'essaie d'accéder à la ressource, j'obtiens cette exception:

SEVERE: A message body writer for Java type, class com.example.MyDto, and MIME media type, application/json, was not found
SEVERE: Mapped exception to response: 500 (Internal Server Error)
javax.ws.rs.WebApplicationException
...

Le cours que j'essaie de servir n'est pas compliqué, il ne contient que des champs finaux publics et un constructeur qui les définit tous. Les champs sont tous des chaînes, primitives, classes similaires à celle-ci ou leurs listes (j'ai essayé d'utiliser des listes simples au lieu de listes génériques <T>, en vain). Est-ce que quelqu'un sait ce qui donne? Merci!

Java EE 6

Jersey 1.1.5

GlassFish 3.0.1

39
Nick

Jersey-json a une implémentation JAXB. La raison pour laquelle vous obtenez cette exception est parce que vous n'avez pas de fournisseur enregistré, ou plus précisément un MessageBodyWriter . Vous devez enregistrer un contexte approprié dans votre fournisseur:

@Provider
public class JAXBContextResolver implements ContextResolver<JAXBContext> {
    private final static String ENTITY_PACKAGE = "package.goes.here";
    private final static JAXBContext context;
    static {
        try {
            context = new JAXBContextAdapter(new JSONJAXBContext(JSONConfiguration.mapped().rootUnwrapping(false).build(), ENTITY_PACKAGE));
        } catch (final JAXBException ex) {
            throw new IllegalStateException("Could not resolve JAXBContext.", ex);
        }
    }

    public JAXBContext getContext(final Class<?> type) {
        try {
            if (type.getPackage().getName().contains(ENTITY_PACKAGE)) {
                return context;
            }
        } catch (final Exception ex) {
            // trap, just return null
        }
        return null;
    }

    public static final class JAXBContextAdapter extends JAXBContext {
        private final JAXBContext context;

        public JAXBContextAdapter(final JAXBContext context) {
            this.context = context;
        }

        @Override
        public Marshaller createMarshaller() {
            Marshaller marshaller = null;
            try {
                marshaller = context.createMarshaller();
                marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
            } catch (final PropertyException pe) {
                return marshaller;
            } catch (final JAXBException jbe) {
                return null;
            }
            return marshaller;
        }

        @Override
        public Unmarshaller createUnmarshaller() throws JAXBException {
            final Unmarshaller unmarshaller = context.createUnmarshaller();
            unmarshaller.setEventHandler(new DefaultValidationEventHandler());
            return unmarshaller;
        }

        @Override
        public Validator createValidator() throws JAXBException {
            return context.createValidator();
        }
    }
}

Ceci recherche un @XmlRegistry dans le nom du package fourni, qui est un package contenant des POJO annotés @XmlRootElement.

@XmlRootElement
public class Person {

    private String firstName;

    //getters and setters, etc.
}

puis créez un ObjectFactory dans le même package:

@XmlRegistry
public class ObjectFactory {
   public Person createNewPerson() {
      return new Person();
   }
}

Avec le @Provider enregistré, Jersey devrait vous faciliter la tâche dans votre ressource:

@GET
@Consumes(MediaType.APPLICATION_JSON)
public Response doWork(Person person) {
   // do work
   return Response.ok().build();
}
12
hisdrewness

Vous pouvez utiliser @XmlRootElement si vous souhaitez utiliser des annotations JAXB (voir autres réponses).

Toutefois, si vous préférez le mappage POJO pur, vous devez procéder comme suit (malheureusement, il n’est pas écrit dans la documentation):

  1. Ajoutez jackson * .jar à votre chemin de classe (comme indiqué par @Vitali Bichov);
  2. Dans web.xml, si vous utilisez le paramètre com.Sun.jersey.config.property.packages init, ajoutez org.codehaus.jackson.jaxrs à la liste. Cela inclura les fournisseurs JSON dans la liste de balayage de Jersey.
15
gamliela

Cela l’a fait pour moi - Jersey 2.3.1

Dans le fichier web.xml:

<servlet>
<servlet-name>Jersey Web Application</servlet-name>
<servlet-class>org.glassfish.jersey.servlet.ServletContainer</servlet-class>
<init-param>
<param-name>jersey.config.server.provider.packages</param-name>
<param-value><my webapp packages>;org.codehaus.jackson.jaxrs</param-value>
</init-param>
</servlet>

Dans le fichier pom.xml:

<dependency>
<groupId>org.glassfish.jersey.media</groupId>
<artifactId>jersey-media-json-jackson</artifactId>
<version>2.3.1</version>
</dependency>
11
yann-h

J'ai suivi les instructions ici qui montrent comment utiliser les POJO de Jersey et de Jackson (par opposition à JAXB). Cela fonctionnait également avec Jersey 1.12. 

10
bytesmith

Vous avez probablement déjà compris cela, mais tout ce que vous avez à faire est d’ajouter ces jars Jackson à votre chemin de classe: jackson-core, jackson-jaxrs, jackson-mapper et jackson-xc

Il semble qu’il existe un autre moyen, comme d’autres l’ont noté. Ajoutez ceci à votre paramètre "com.Sun.jersey.config.property.packages" (si vous utilisez Tomcat et web.xml): "org.codehaus.jackson.jaxrs", comme suit:

<init-param>
  <param-name>com.Sun.jersey.config.property.packages</param-name>
  <param-value>org.codehaus.jackson.jaxrs</param- value>
</init-param>

Cela nécessitera également les mêmes pots Jackson sur votre chemin de classe

3
ChrisO

Pourquoi utilisez-vous les champs finaux? J'utilise jersey et j'ai quelques objets/pojos JAXB et tout ce que j'avais à faire était tout simplement d'annoter ma méthode de ressource avec @Produces ("application/json") et cela fonctionne sans problème. la boîte. Je n'ai pas eu à jouer avec le web.xml. Assurez-vous simplement que vos pojos sont correctement annotés.

Voici un simple pojo

package test;

import javax.xml.bind.annotation.XmlRootElement;

@XmlRootElement
public class SampleJaxbObject {

    private String field1;

    private Integer field2;

    private String field3;

    public String getField1() {
        return field1;
    }

    public void setField1(String field1) {
        this.field1 = field1;
    }

    public Integer getField2() {
        return field2;
    }

    public void setField2(Integer field2) {
        this.field2 = field2;
    }

    public String getField3() {
        return field3;
    }

    public void setField3(String field3) {
        this.field3 = field3;
    }


}
3
Ricardo Riveros

Jersey 2.0 prend en charge JSON avec MOXy et Jackson.

La prise en charge de MOXy est activée par défaut si le fichier JAR existe dans le chemin de classe et la prise en charge de Jackson peut être activée à l'aide d'une fonction. Tout cela est expliqué en détail dans le chapitre Guide de l'utilisateur Jersey 2.0 sur la liaison JSON:

https://jersey.Java.net/documentation/latest/media.html#json

Pour ajouter la prise en charge de MOXy sans nécessiter de configuration, ajoutez la dépendance suivante à votre maven pom.xml

<dependency>
    <groupId>org.glassfish.jersey.media</groupId>
    <artifactId>jersey-media-moxy</artifactId>
    <version>2.6</version>
</dependency>
3
Arun Gupta

Je suis novice dans ce domaine mais j’ai pu utiliser des POJO après avoir ajouté le fichier jackson-all-1.9.0.jar au chemin de classe.

2
Vitali Bichov

Ce qui suit a fonctionné pour moi. J'utilise Jersey 2.7 avec Jackson avec Apache Felix (OSGi) s'exécutant sur Tomcat6.

public class MyApplication extends ResourceConfig {

    public MyApplication() {
        super(JacksonFeature.class);
        // point to packages containing your resources
        packages(getClass().getPackage().getName());
    }
}

Et ensuite, dans votre web.xml (ou dans mon cas, juste une Hashtable), vous spécifieriez votre javax.ws.rs.Application comme suit

<init-param>
    <param-name>javax.ws.rs.Application</param-name>
    <param-value><MyApplication.class.getName()></param-value>
</init-param>

Pas besoin de spécifier com.Sun.jersey.config.property.pacakges ou com.Sun.jersey.api.json.POJOMappingFeature

Assurez-vous simplement que vous spécifiez la dépendance sur 

<dependency>
    <groupId>org.glassfish.jersey.media</groupId>
    <artifactId>jersey-media-json-jackson</artifactId>
    <version>2.7</version>
</dependency>
1
shreyas

Déplacer la dépendance jersey-json au sommet du fichier pom.xml a résolu ce problème pour moi.

<dependencies>
  <dependency>
    <groupId>com.Sun.jersey</groupId>
    <artifactId>jersey-json</artifactId>
    <version>1.18.1</version>
  </dependency>

  <!-- other dependencies -->

</dependencies>
1
supercobra