Jak deserializować listę za pomocą GSON lub innej biblioteki JSON w Javie?

121

Mogę serializować List<Video>w moim serwlecie na GAE, ale nie mogę go deserializować. Co ja robię źle?

To jest wideo mojej klasy w GAE, które jest serializowane:

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

}

To jest moja klasa wideo w mojej innej aplikacji, w której próbuję deserializować:

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
źródło
Do Twojej wiadomości, od wersji Gson 1.7 konstruktor no-args nie jest już wymagany. Zobacz groups.google.com/group/google-gson/browse_thread/thread/… Miłego kodowania.
Joel

Odpowiedzi:

328

W przypadku Gson wystarczy zrobić coś takiego:

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

Może być również konieczne podanie konstruktora bez argumentów dla Videoklasy, do której deserializujesz.

ColinD
źródło
Koleś, jesteś niesamowity, bardzo dziękuję, to działa. Mój błąd nie polegał na stworzeniu konstruktora bez argumentów. Dziękuję bardzo!
Valter Silva
4
Co to jest {} w klauzuli new TypeToken <List <Video>> () {}. GetType ()? Jak to jest legalna składnia Java?
Maxim Veksler,
8
@Maxim: Tworzy anonimową podklasę TypeToken<List<Video>>... to sztuczka, która pozwala wynikowemu typowi reprezentować List<Video>, ponieważ podklasy w pełni określonych typów ogólnych zachowują informacje o typie ogólnym.
ColinD
1
Wersja 2.1 Gson ma teraz domyślny konstruktor dostępu ... stąd nie możemy użyć powyższego kodu ... zamiast tego teraz klasa TypeToken ma następującą metodę: public static TypeToken <?> Get (Type type) {return new TypeToken (type); } Ale w tym przypadku ... jak moglibyśmy podać mu właściwy typ ???
Pablo
1
@Pablo: Wydaje mi się, że konstruktor bez argonu TypeTokennadal jest protectedw Gson 2.1, więc powyższe powinno nadal działać.
ColinD
108

Innym sposobem jest użycie tablicy jako typu, np:

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

W ten sposób unikniesz wszystkich kłopotów z obiektem Type, a jeśli naprawdę potrzebujesz listy, zawsze możesz przekonwertować tablicę na listę, np:

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

IMHO to jest znacznie bardziej czytelne.


W Kotlinie wygląda to tak:

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

Aby przekonwertować tę tablicę na List, po prostu użyj .toList()metody method

DevNG
źródło
1
Przyjęta odpowiedź jest dobra, ale wolę to, ponieważ wszystko, czego naprawdę potrzebowałem, to lista rzeczy i tablica wystarczająca, aby służyć jako „lista rzeczy”
smac89
10

Wypróbuj tę jedną linijkę

List<Video> videos = Arrays.asList(new Gson().fromJson(json, Video[].class));

Uwaga: lista videoszwrócona przez Arrays.asListjest niezmienna - nie można wstawiać nowych wartości.


Odniesienie:

  1. Tablice metod # asList
  2. Konstruktor Gson
  3. Metoda Gson # fromJson (źródło jsonmoże być typu JsonElement, Readerlub String)
  4. Lista interfejsów
  5. JLS - tablice
  6. JLS - Generic Interfaces
naXa
źródło
2

Uważaj, korzystając z odpowiedzi udzielonej przez @DevNG. Arrays.asList () zwraca wewnętrzną implementację ArrayList, która nie implementuje niektórych użytecznych metod, takich jak add (), delete () itp. Jeśli je wywołasz, zostanie wyrzucony wyjątek UnsupportedOperationException. Aby uzyskać prawdziwą instancję ArrayList, musisz napisać coś takiego:

List<Video> = new ArrayList<>(Arrays.asList(videoArray));
Bogdan Kornev
źródło
wat? Arrays.asList zwraca interfejs List, który udostępnia również funkcje add () i remove ()!
Enrichman
2
@Enrichman: Arrays.asList () zwraca listę o stałym rozmiarze wspieraną przez określoną tablicę. Ta implementacja ArrayList rozszerza klasę AbstractList i nie przesłania metody remove (int index) z klasy bazowej. A jeśli spojrzysz na kod źródłowy AbstractList.remove (indeks int), zobaczysz, że zawsze jest on generowany jako UnsupportedOperationException. To samo dotyczy metody add ().
Bogdan Kornev
1
Wo, to dość brzydkie, nie wiedziałem tego. Dzięki za wskazanie tego. :)
Enrichman