web-dev-qa-db-fra.com

Jersey: impossible de désérialiser une instance de ArrayList en sortie de chaîne

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:

Le client Jersey ne peut pas désérialiser les services JSON - exception (ne peut pas désérialiser l'instance)

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!

11
lpinto.eu

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:

  1. Utilisez Jackson
  2. Forcer l'utilisation des fournisseurs
  3. Définir un désérialiseur personnalisé
  4. activer l'indicateur ACCEPT_SINGLE_VALUE_AS_ARRAY
  5. Réparer les dépendances

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:

Customizing-ObjectMapper

Après tout cela, cela ne fonctionnait toujours pas ...

Après un peu plus de temps de recherche, j'ai trouvé:

Jackson 2.0 avec Jersey 1.12

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:

jackson-jaxrs-json-provider

Remarque: cette modification supprime la capacité de Jersey à utiliser Jaxb ou Jettison.

Hors sujet , peut être intéressant pour quelqu'un:

Configurez Jersey/Jackson pour qu'il n'utilise PAS l'annotation de champ @XmlElement pour l'attribution de nom de champ JSON

11
lpinto.eu

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;
}
2
steven35

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().

1
rmhartog

Cela a fonctionné pour moi en ajoutant @JsonSerialize à la classe

@JsonSerialize
Public class Person {
    List<String> names;
}
1
Manju
{"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

1
Zaric