Como desserializar uma lista usando o GSON ou outra biblioteca JSON em Java?

121

Eu posso serializar um List<Video> no meu servlet no GAE, mas não posso desserializá-lo. O que estou fazendo de errado?

Esta é a minha classe Vídeo no GAE, que é serializada:

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

}

Esta é a minha classe Video em meu outro aplicativo, onde tento desserializar:

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
fonte
Para sua informação, a partir do Gson 1.7, o construtor no-args não é mais necessário. Consulte groups.google.com/group/google-gson/browse_thread/thread/… Feliz codificação.
Joel

Respostas:

328

Com o Gson, você só precisa fazer algo como:

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

Você também pode precisar fornecer um construtor sem argumento na Videoclasse para a qual está desserializando.

ColinD
fonte
Cara, você é incrível, muito obrigado, funciona. Meu erro não foi criar um construtor sem argumentos. Muito obrigado!
Valter Silva
4
O que é o {} na cláusula new TypeToken <List <Video>> () {}. GetType ()? Como é a sintaxe java legal?
Maxim Veksler
8
@ Maxim: Ele está criando uma subclasse anônima de TypeToken<List<Video>>... é um truque que permite que o tipo resultante represente List<Video>, já que subclasses de tipos genéricos totalmente especificados retêm as informações do tipo genérico.
ColinD
1
A versão 2.1 do Gson agora tem um construtor de acesso padrão ... portanto, não podemos usar o código acima ... em vez disso, agora a classe TypeToken possui o seguinte método: public static TypeToken <?> Get (Type type) {return new TypeToken (tipo); } Mas neste caso ... como poderíamos fornecer o tipo correto para ele ???
Pablo # 19
1
@ Pablo: Parece-me que o construtor no-arg TypeTokenainda está protectedno Gson 2.1, portanto o que precede ainda deve funcionar.
colind
108

Outra maneira é usar uma matriz como um tipo, por exemplo:

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

Dessa forma, você evita todos os problemas com o objeto Type e, se realmente precisa de uma lista, pode sempre converter a matriz em uma lista, por exemplo:

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

IMHO isso é muito mais legível.


No Kotlin, é assim:

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

Para converter essa matriz em lista, basta usar o .toList()método

DevNG
fonte
1
A resposta aceita é bom, mas eu prefiro isso desde que tudo o que eu realmente queria é uma lista de coisas e matriz é suficiente para servir como uma "lista de coisas"
smac89
2

Cuidado ao usar a resposta fornecida por @DevNG. Arrays.asList () retorna a implementação interna de ArrayList que não implementa alguns métodos úteis como add (), delete () etc. Se você os chamar, uma UnsupportedOperationException será lançada. Para obter uma instância real de ArrayList, você precisa escrever algo como isto:

List<Video> = new ArrayList<>(Arrays.asList(videoArray));
Bogdan Kornev
fonte
wat? Arrays.asList retorna uma interface de lista, que fornece add () e remove () também!
Enrichman
2
@Enrichman: Arrays.asList () retorna uma lista de tamanho fixo apoiada pela matriz especificada. Essa implementação ArrayList estende uma classe AbstractList e não substitui o método remove (int index) da classe base. E se você olhar para o código fonte do AbstractList.remove (int index), você o verá sempre lançado UnsupportedOperationException. O mesmo é para o método add ().
Bogdan Kornev
1
Uau, isso é muito feio, eu não sabia disso. Obrigado por apontar isso. :)
Enrichman