Как десериализовать список с помощью GSON или другой библиотеки JSON на Java?

121

Я могу сериализовать a List<Video>в своем сервлете в GAE, но не могу десериализовать его. Что я делаю не так?

Это мой класс Video в GAE, который сериализован:

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

}

Это мой класс Video в другом моем приложении, где я пытаюсь десериализовать:

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

}
Вальтер Сильва
источник
К вашему сведению, начиная с Gson 1.7 конструктор без аргументов больше не требуется. См. Groups.google.com/group/google-gson/browse_thread/thread/… Удачного кодирования.
Джоэл

Ответы:

328

С Gson вам просто нужно сделать что-то вроде:

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

Вам также может потребоваться предоставить конструктор без аргументов для Videoкласса, в который вы десериализуетесь.

ColinD
источник
Чувак, ты потрясающий, спасибо тебе огромное, это работает. Моя ошибка заключалась не в создании конструктора без аргументов. Спасибо вам большое!
Вальтер Сильва
4
Что означает {} в предложении new TypeToken <List <Video>> () {}. GetType ()? Насколько это законный синтаксис Java?
Максим Векслер
8
@Maxim: он создает анонимный подкласс TypeToken<List<Video>>... это трюк, позволяющий представлять результирующий тип List<Video>, поскольку подклассы полностью определенных универсальных типов сохраняют информацию об общем типе.
ColinD
1
Версия Gson 2.1 теперь имеет конструктор доступа по умолчанию ... следовательно, мы не можем использовать приведенный выше код ... вместо этого теперь класс TypeToken имеет следующий метод: public static TypeToken <?> Get (Type type) {return new TypeToken (тип); } Но в этом случае ... как мы можем указать ему правильный тип ???
Пабло
1
@Pablo: Мне кажется, что конструктор без аргументов для TypeTokenвсе еще находится protectedв Gson 2.1, поэтому все вышесказанное должно работать.
ColinD
108

Другой способ - использовать массив как тип, например:

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

Таким образом вы избегаете всех хлопот с объектом Type, и если вам действительно нужен список, вы всегда можете преобразовать массив в список, например:

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

ИМХО это намного читабельнее.


В Котлине это выглядит так:

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

Чтобы преобразовать этот массив в список, просто используйте .toList()метод

DevNG
источник
1
Принятый ответ хорош, но я предпочитаю его, так как все, что мне действительно нужно, это список вещей, а массив достаточен, чтобы служить «списком вещей»
smac89
10

Попробуйте этот однострочный

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

Предупреждение: список videos, возвращаемый Arrays.asListфункцией, неизменен - ​​вы не можете вставлять новые значения.


Ссылка:

  1. Массивы методов # asList
  2. Конструктор Гсон
  3. Метод Gson # fromJson (источник jsonможет быть типа JsonElement, Readerили String)
  4. Список интерфейсов
  5. JLS - Массивы
  6. JLS - общие интерфейсы
naXa
источник
2

Будьте осторожны, используя ответ @DevNG. Arrays.asList () возвращает внутреннюю реализацию ArrayList, которая не реализует некоторые полезные методы, такие как add (), delete () и т. Д. Если вы их вызовете, будет выброшено исключение UnsupportedOperationException. Чтобы получить настоящий экземпляр ArrayList, вам нужно написать что-то вроде этого:

List<Video> = new ArrayList<>(Arrays.asList(videoArray));
Богдан Корнев
источник
Wat? Arrays.asList возвращает интерфейс List, который также поддерживает add () и remove ()!
Enrichman
2
@Enrichman: Arrays.asList () возвращает список фиксированного размера, поддерживаемый указанным массивом. Эта реализация ArrayList расширяет класс AbstractList и не переопределяет метод remove (int index) из базового класса. И если вы посмотрите исходный код AbstractList.remove (int index), вы увидите, что он всегда генерирует исключение UnsupportedOperationException. То же самое и с методом add ().
Богдан Корнев
1
Вау, это довольно уродливо, я этого не знала. Спасибо, что указали на это. :)
Enrichman