J'ai un service Web basé sur JSON REST implémenté à l'aide de: Jetty, Jersey, Jersey-JSON utilisant Jackson.
Une de mes méthodes reçoit une instance Person, qui a un champ de type List <String>. C'est-à-dire:
Public class Person {
List<String> names;
}
Si je l'appelle avec un tableau de noms, tout va bien! par exemple.:
{ "names" : [ "Jhon", "Doe" ] }
Mais si la personne n'a qu'un nom, mon client crée un seul élément de valeur, par exemple:
{ "names" : "Jhon" }
Lorsque j'essaie d'appeler le service avec une seule valeur, j'obtiens une exception:
Can not deserialize instance of Java.util.ArrayList out of VALUE_STRING token
Question:
Comment dois-je créer/configurer mon service Web, afin de pouvoir désérialiser le champ du tableau quand ils me sont envoyés en tant qu'élément unique.
-
J'ai déjà lu:
Désérialisation de Jackson - avec contenu ArrayList <T>
et
Comment personnaliser la sérialisation d'une liste d'objets JAXB en JSON?
et ceci qui renvoie à la dernière réponse:
Jaxb json manquant de crochets pour un tableau d'éléments
Mais aucun de ceux-ci ne résout le problème.
Merci d'avance!
Après une longue journée et une autre ... après avoir lu beaucoup de wikis et de faq, cela fonctionne enfin.
Ce que j'ai fait:
L'histoire:
J'utilisais Jersey 1.13 qui utilise (je crois) jaxb par défaut.
Je l'ai changé en use Jackson
<init-param>
<param-name>com.Sun.jersey.api.json.POJOMappingFeature</param-name>
<param-value>true</param-value>
</init-param>
comme décrit à:
https://stackoverflow.com/a/13895768/660990
Cela a obligé mon maillot à utiliser Jackson, mais le problème demeure; Jackson ne peut pas encore désérialiser le tableau.
J'ai forcé l'utilisation de fournisseurs de Jackson :
<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>
https://stackoverflow.com/a/3143214/660990
Était une étape nécessaire, mais pas suffisante. Il est nécessaire d'activer le ACCEPT_SINGLE_VALUE_AS_ARRAY flag.
ObjectMapper objectMapper;
objectMapper = new ObjectMapper().configure(DeserializationFeature.ACCEPT_SINGLE_VALUE_AS_ARRAY, true);
J'avais besoin de définir désérialiseur personnalisé
public class MyResolver implements ContextResolver<ObjectMapper> {
@Override
public ObjectMapper getContext(final Class<?> objectType) {
...
return objectMapper;
}
}
pour pouvoir faire ça:
Après tout cela, cela ne fonctionnait toujours pas ...
Après un peu plus de temps de recherche, j'ai trouvé:
Cela discute problèmes de dépendances ..
Cela a révélé mon problème, Jersey v1.13 est livré avec Jackson v1.9.2 J'ai besoin de Jackson v2.0
J'ai supprimé la dépendance pour jersey-json, car elle incluait jackson 1.9.2:
<dependency>
<groupId>com.Sun.jersey</groupId>
<artifactId>jersey-json</artifactId>
</dependency>
Et directement déclaré dépendance pour:
<dependency>
<groupId>com.fasterxml.jackson.jaxrs</groupId>
<artifactId>jackson-jaxrs-json-provider</artifactId>
</dependency>
Référence:
Remarque: cette modification supprime la capacité de Jersey à utiliser Jaxb ou Jettison.
Hors sujet , peut être intéressant pour quelqu'un:
Vous pouvez le faire avec des annotations au niveau de la classe, du champ ou de la méthode à l'aide de JsonFormat annotation
@JsonFormat(with = Feature.ACCEPT_SINGLE_VALUE_AS_ARRAY)
protected List<String> list;
public List<String> getList() {
return list;
}
public void setList(List<String> list) {
this.list = list;
}
Les exemples 5.10 et 5.11 de cette page expliquent votre problème exact. Vous pouvez configurer le générateur JSON pour forcer les tableaux pour les listes à élément unique, comme suit: JSONConfiguration.mapped().arrays("names").build()
.
Cela a fonctionné pour moi en ajoutant @JsonSerialize à la classe
@JsonSerialize
Public class Person {
List<String> names;
}
{"results": {"place": {"lang": "en-US","woeid": "2168606"}}}
Et
{"results": {"place": [{"lang": "en-US","woeid": "2168606"}, {"lang": "en-US","woeid": "2168606"}]}}
ce type comment faire ... lors de l'utilisation de Yahoo place api