¿Cómo deserializar una lista usando GSON u otra biblioteca JSON en Java?

121

Puedo serializar un List<Video>en mi servlet en GAE, pero no puedo deserializarlo. ¿Qué estoy haciendo mal?

Este es mi video de clase en GAE, que está serializado:

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

}

Este es mi video de clase en mi otra aplicación, donde trato de deserializar:

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
fuente
FYI, a partir de Gson 1.7, el constructor no-args ya no es necesario. Consulta groups.google.com/group/google-gson/browse_thread/thread/… Happy coding.
Joel

Respuestas:

328

Con Gson, solo necesitaría hacer algo como:

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

Es posible que también deba proporcionar un constructor sin argumentos en la Videoclase a la que está deserializando.

ColinD
fuente
Amigo, eres increíble, muchas gracias, funciona. Mi error fue no crear un constructor sin argumentos. Muchas gracias!
Valter Silva
4
¿Cuál es el {} en la cláusula new TypeToken <List <Video>> () {}. GetType ()? ¿Cómo es la sintaxis de Java legal?
Maxim Veksler
8
@Maxim: Está creando una subclase anónima de TypeToken<List<Video>>... es un truco que permite que el tipo resultante se represente List<Video>, ya que las subclases de tipos genéricos completamente especificados retienen la información del tipo genérico.
ColinD
1
La versión 2.1 de Gson ahora tiene un constructor de acceso predeterminado ... por lo tanto, no podemos usar el código anterior ... en cambio, ahora la clase TypeToken tiene el siguiente método: public static TypeToken <?> Get (Type type) {return new TypeToken (tipo); } Pero en este caso ... ¿cómo podemos proporcionarle el tipo correcto ???
Pablo
1
@Pablo: Me parece que el constructor sin argumentos para TypeTokentodavía está protecteden Gson 2.1, por lo que lo anterior aún debería funcionar.
ColinD
108

Otra forma es usar una matriz como tipo, por ejemplo:

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

De esta manera, evita todas las molestias con el objeto Type, y si realmente necesita una lista, siempre puede convertir la matriz en una lista, por ejemplo:

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

En mi humilde opinión, esto es mucho más legible.


En Kotlin, esto se ve así:

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

Para convertir esta matriz en Lista, solo use el .toList()método

DevNG
fuente
1
La respuesta aceptada es buena, pero prefiero esto ya que todo lo que realmente quería es una lista de cosas y la matriz es suficiente para servir como una "lista de cosas"
smac89
2

Tenga cuidado al usar la respuesta proporcionada por @DevNG. Arrays.asList () devuelve la implementación interna de ArrayList que no implementa algunos métodos útiles como add (), delete (), etc. Si los llama, se lanzará una UnsupportedOperationException. Para obtener una instancia real de ArrayList, debe escribir algo como esto:

List<Video> = new ArrayList<>(Arrays.asList(videoArray));
Bogdan Kornev
fuente
¿Wat? Arrays.asList devuelve una interfaz List, que también proporciona add () y remove ().
Enrichman
2
@Enrichman: Arrays.asList () devuelve una lista de tamaño fijo respaldada por la matriz especificada. Esta implementación de ArrayList extiende una clase AbstractList y no anula el método remove (int index) de la clase base. Y si observa el código fuente de AbstractList.remove (int index), verá que siempre arroja UnsupportedOperationException. Lo mismo es para el método add ().
Bogdan Kornev
1
Wo, eso es bastante feo, no lo sabía. Gracias por mencionarlo. :)
Enrichman