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.
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!
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;
}
}
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?
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.
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>
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
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>