Comment désérialiser une liste à l'aide de GSON ou d'une autre bibliothèque JSON en Java?

121

Je peux sérialiser un List<Video>dans mon servlet sur GAE, mais je ne peux pas le désérialiser. Qu'est-ce que je fais mal?

Ceci est ma vidéo de classe dans GAE, qui est sérialisée:

package legiontube;

import java.util.Date;

import javax.jdo.annotations.IdGeneratorStrategy;
import javax.jdo.annotations.IdentityType;
import javax.jdo.annotations.PersistenceCapable;
import javax.jdo.annotations.Persistent;
import javax.jdo.annotations.PrimaryKey;

@PersistenceCapable(identityType = IdentityType.APPLICATION)
public class Video {

    @PrimaryKey
    private String id;

    @Persistent
    private String titulo;

    @Persistent
    private String descricao;

    @Persistent
    private Date date;

    public Video(){};

 public Video(String id, String titulo, String descricao, Date date) {
  //super();
  this.id = id;
  this.titulo = titulo;
  this.descricao = descricao;
  this.date = date;
 }

 public String getId() {
  return id;
 }

 public void setId(String id) {
  this.id = id;
 }

 public String getTitulo() {
  return titulo;
 }

 public void setTitulo(String titulo) {
  this.titulo = titulo;
 }

 public String getDescricao() {
  return descricao;
 }

 public void setDescricao(String descricao) {
  this.descricao = descricao;
 }

 public Date getDate() {
  return date;
 }

 public void setDate(Date date) {
  this.date = date;
 }

}

Voici ma vidéo de classe dans mon autre application, où j'essaye de désérialiser:

package classes;

import java.util.Date;

public class Video {
 private String id;
 private String titulo;
 private String descricao;
 private Date date;

 public Video(String id, String titulo, String descricao, Date date) {
  //super();
  this.id = id;
  this.titulo = titulo;
  this.descricao = descricao;
  this.date = date;
 }

 public String getId() {
  return id;
 }
 public void setId(String id) {
  this.id = id;
 }
 public String getTitulo() {
  return titulo;
 }
 public void setTitulo(String titulo) {
  this.titulo = titulo;
 }
 public String getDescricao() {
  return descricao;
 }
 public void setDescricao(String descricao) {
  this.descricao = descricao;
 }
 public Date getDate() {
  return date;
 }
 public void setDate(Date date) {
  this.date = date;
 }

}
Valter Silva
la source
Pour info, depuis Gson 1.7, le constructeur no-args n'est plus nécessaire. Voir groups.google.com/group/google-gson/browse_thread/thread/… Bon codage.
Joel

Réponses:

328

Avec Gson, il vous suffit de faire quelque chose comme:

List<Video> videos = gson.fromJson(json, new TypeToken<List<Video>>(){}.getType());

Vous devrez peut-être également fournir un constructeur sans argument sur la Videoclasse vers laquelle vous désérialisez.

ColinD
la source
Mec, tu es incroyable, merci beaucoup, ça marche. Mon erreur n'a pas été de créer un constructeur sans argument. Merci beaucoup!
Valter Silva
4
Quel est le {} dans la clause new TypeToken <List <Video>> () {}. GetType ()? Comment est-ce la syntaxe légale Java?
Maxim Veksler
8
@Maxim: Cela crée une sous-classe anonyme de TypeToken<List<Video>>... c'est une astuce qui permet au type résultant de se représenter List<Video>, puisque les sous-classes de types génériques entièrement spécifiés conservent les informations de type générique.
ColinD
1
La version 2.1 de Gson a maintenant un constructeur d'accès par défaut ... donc nous ne pouvons pas utiliser le code ci-dessus ... à la place maintenant, la classe TypeToken a la méthode suivante: public static TypeToken <?> Get (Type type) {return new TypeToken (type); } Mais dans ce cas ... comment pourrions-nous lui fournir le type correct ???
Pablo
1
@Pablo: Il me semble que le constructeur no-arg pour TypeTokenest toujours protecteddans Gson 2.1, donc ce qui précède devrait toujours fonctionner.
ColinD le
108

Une autre façon est d'utiliser un tableau comme type, par exemple:

Video[] videoArray = gson.fromJson(json, Video[].class);

De cette façon, vous évitez tous les tracas avec l'objet Type, et si vous avez vraiment besoin d'une liste, vous pouvez toujours convertir le tableau en une liste, par exemple:

List<Video> videoList = Arrays.asList(videoArray);

IMHO c'est beaucoup plus lisible.


À Kotlin, cela ressemble à ceci:

Gson().fromJson(jsonString, Array<Video>::class.java)

Pour convertir ce tableau en liste, utilisez simplement la .toList()méthode

DevNG
la source
1
La réponse acceptée est bonne, mais je préfère celle-ci car tout ce que je voulais vraiment est une liste de choses et le tableau est suffisant pour servir de "liste de choses"
smac89
2

Soyez prudent en utilisant la réponse fournie par @DevNG. Arrays.asList () retourne l'implémentation interne d'ArrayList qui n'implémente pas certaines méthodes utiles comme add (), delete (), etc. Si vous les appelez, une exception UnsupportedOperationException sera lancée. Pour obtenir une véritable instance ArrayList, vous devez écrire quelque chose comme ceci:

List<Video> = new ArrayList<>(Arrays.asList(videoArray));
Bogdan Kornev
la source
wat? Arrays.asList renvoie une interface List, qui fournit également add () et remove ()!
Enrichman
2
@Enrichman: Arrays.asList () renvoie une liste de taille fixe soutenue par le tableau spécifié. Cette implémentation ArrayList étend une classe AbstractList et ne remplace pas la méthode remove (int index) de la classe de base. Et si vous regardez le code source de AbstractList.remove (index int), vous verrez qu'il est toujours levé UnsupportedOperationException. Il en va de même pour la méthode add ().
Bogdan Kornev
1
Wo, c'est assez moche, je ne le savais pas. Merci de l'avoir signalé. :)
Enrichman