web-dev-qa-db-fra.com

Jersey: le tableau Json avec 1 élément est sérialisé en tant qu'objet

Je crée un serveur REST avec Jersey/Java et j'ai constaté un comportement étrange.

J'ai une méthode sur le serveur qui retourne un tableau d'objets comme Json

@GET
@Path("/files")
@Produces(MediaType.APPLICATION_JSON)
public Object getFiles() throws Exception{
    DatabaseManager db = new DatabaseManager();
    FileInfo[] result = db.getFiles();
    return result;
}

Le code est exécuté correctement et les données sont renvoyées au client (appel jQuery ajax) . Le problème est que le format des données renvoyées change si le tableau "result" comporte un ou plusieurs éléments.

Réponse avec un élément:

{"fileInfo":{"fileName":"weather.arff","id":"10"}}

Réponse avec deux éléments:

{"fileInfo":[{"fileName":"weather.arff","id":"10"},{"fileName":"supermarket.arff","id":"11"}]}

Comme vous pouvez le constater, dans le premier scénario, la valeur de la propriété "fileInfo" de l'objet renvoyé est un objet et, dans le second cas, la valeur est un tableau . Le premier cas ne devrait-il pas renvoyer quelque chose comme ceci:

{"fileInfo":[{"fileName":"weather.arff","id":"10"}]}

c'est-à-dire un tableau avec un seul objet à l'intérieur?

Je sais que je peux détecter cela du côté client, mais cela semble être un bidouillage très laid.

Merci pour votre temps.

26
willvv

J'ai fini par utiliser Jackson, également décrit dans la documentation officielle de Jersey (http://jersey.Java.net/nonav/documentation/latest/user-guide.html#json.pojo.approach.section).

J'avais déjà essayé cela, mais cela ne fonctionnait pas car je n'avais pas le pot Jackson dans le chemin de construction de mon projet (d'après la documentation, je pensais qu'il était intégré à la bibliothèque principale de jersey).

Je viens d'ajouter le fichier jackson-all.jar (http://wiki.fasterxml.com/JacksonDownload) et d'activer le support de POJO dans la configuration. 

    <init-param>
          <param-name>com.Sun.jersey.api.json.POJOMappingFeature</param-name>
          <param-value>true</param-value>
    </init-param>

Et voila!

12
willvv

Si vous utilisiez JAXB pour générer un résultat JSON, vous pouvez configurer le processeur JSON de Jersey pour obtenir un format JSON plus important.

document officiel du maillot a une config détaillée:

Pour obtenir des modifications de format JSON plus importantes, vous devez configurer le proceseur JSON Jersey lui-même. Diverses options de configuration peuvent être définies sur une instance JSONConfiguration. L'instance pourrait ensuite être utilisée pour créer un JSONJAXBContext JSONConfiguré, qui sert de point de configuration principal dans cette zone. Pour transmettre votre jSONJAXBContext spécialisé à Jersey, vous devez enfin implémenter un ContextResolver JAXBContext:

    @Provider
public class JAXBContextResolver implements ContextResolver<JAXBContext> {
    private final JAXBContext context;
    private final Set<Class> types;
    private Class[] ctypes = { FileInfo.class}; //your pojo class
    public JAXBContextResolver() throws Exception {
        this.types = new HashSet(Arrays.asList(ctypes));
        this.context = new JSONJAXBContext(JSONConfiguration.natural().build(),
                ctypes); //json configuration
    }

    @Override
    public JAXBContext getContext(Class<?> objectType) {
        return (types.contains(objectType)) ? context : null;
    }
}
5
secondflying

Jetez également un coup d'œil à la réponse suivante qui m'a résolu le problème:

Comment personnaliser la sérialisation d'une liste d'objets JAXB en JSON?

1
chrset

Vous pouvez également essayer la bibliothèque Genson http://code.google.com/p/genson/ . Il s’intègre bien au maillot, il suffit de déposer le pot dans votre chemin de classe et tout fonctionnera. Il ne vous oblige pas à écrire du code supplémentaire, cela devrait fonctionner comme ce que vous avez maintenant, mais sans résultat étrange. 

0
eugen
I'm using cxf, here is my applicationContext.xml to force array in JSON, 
<jaxrs:server id="myService" serviceName="MyService"
address="/mysvc">
<jaxrs:serviceBeans>
    <ref bean="myServiceImpl"/>
</jaxrs:serviceBeans>
<jaxrs:providers>
    <bean class="org.Apache.cxf.jaxrs.provider.json.JSONProvider">
   <property name="dropRootElement" value="true" />
   <property name="supportUnwrapped" value="true" />
   <property name="namespaceMap">
      <map>
        <entry key="http://example.com/myservice" value=""/>
      </map>
   </property>
   <property name="arrayKeys">
      <list>
    <value>fileInfo</value>
      </list>
   </property>                          
    </bean>
</jaxrs:providers>
</jaxrs:server>
0
Lance

Vous pouvez utiliser Jettison (avec Jersey) et préparer la structure que vous souhaitez utiliser en utilisant JSONObject et JSONArray comme valeurs de retour . Elles se trouvent dans le package org.codehaus.jettison.json de jettison-1.3.2.jar, qui est une dépendance transitive de jerysey-json

0
Fabian Lange

J'ai pas mal lutté et trouvé cette solution simple

Dans votre pom.xml:

<dependency>
    <groupId>org.codehaus.jackson</groupId>
    <artifactId>jackson-jaxrs</artifactId>
    <version>1.9.13</version>
</dependency>
<dependency>
    <groupId>org.codehaus.jackson</groupId>
    <artifactId>jackson-xc</artifactId>
    <version>1.9.13</version>
</dependency>

Dans votre web.xml:

<servlet-class>com.Sun.jersey.spi.container.servlet.ServletContainer</servlet-class>
<init-param>
    <param-name>com.Sun.jersey.config.property.packages</param-name>
    <param-value>com.other-packages;org.codehaus.jackson.jaxrs</param-value>
</init-param>
0
Nicholas Ng