141

I can serialize a List<Video> in my servlet on GAE, but I can't deserialize it. What am I doing wrong?

This is my class Video in GAE, which is serialized:

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

}

This is my class Video in my other application, where I try to deserialize:

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

}
Gama11
  • 31,714
  • 9
  • 78
  • 100
Valter Silva
  • 16,446
  • 52
  • 137
  • 218
  • FYI, As of Gson 1.7, the no-args constructor is no longer required. See http://groups.google.com/group/google-gson/browse_thread/thread/6272c9be58676e47# Happy coding. – Joel Apr 13 '11 at 08:15

4 Answers4

371

With Gson, you'd just need to do something like:

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

You might also need to provide a no-arg constructor on the Video class you're deserializing to.

ColinD
  • 108,630
  • 30
  • 201
  • 202
  • 1
    Dude, you are amazing, thank you so much, it works. My mistake was not create a constructor with no args. Thank you so much! – Valter Silva Nov 30 '10 at 23:48
  • 6
    What is the {} in the clause new TypeToken>(){}.getType() ? How is it legal java syntax? – Maxim Veksler Dec 10 '10 at 00:29
  • 9
    @Maxim: It's making an anonymous subclass of `TypeToken>`... it's a trick that allows the resulting type to represent `List – ColinD Dec 10 '10 at 07:30
  • 1
    The 2.1 version of Gson now has a default access constructor... hence we can't use the code above... instead now the TypeToken class has the following method: public static TypeToken> get(Type type) { return new TypeToken(type); } But in this case... how could we provide the correct type to it??? – Pablo Apr 03 '12 at 20:19
  • 1
    @Pablo: It looks to me like the no-arg constructor for `TypeToken` is still `protected` in Gson 2.1, so the above should still work. – ColinD Apr 03 '12 at 22:05
  • Note that you *cannot do this with an unknown generic type parameter*. https://stackoverflow.com/questions/18320562/deserialise-a-generic-list-in-gson – forresthopkinsa May 22 '18 at 17:34
  • If I know the average amount of elements, is there a way to allocate the list with the that size? – ChRoNoN Jul 03 '18 at 01:20
  • imports: ```import java.lang.reflect.Type; import com.google.gson.reflect.TypeToken;``` – Filomat Feb 15 '20 at 17:32
124

Another way is to use an array as a type, e.g.:

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

This way you avoid all the hassle with the Type object, and if you really need a list you can always convert the array to a list, e.g.:

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

IMHO this is much more readable.


In Kotlin this looks like this:

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

To convert this array into List, just use .toList() method

soshial
  • 5,906
  • 6
  • 32
  • 40
DevNG
  • 5,875
  • 3
  • 18
  • 14
  • 1
    The accepted answer is good, but I prefer this since all I really wanted is a list of stuff and array is sufficient to serve as a "list of stuff" – smac89 Nov 10 '15 at 01:02
  • ah thank you I was trying `List – orpheus Mar 24 '22 at 20:56
14

I recomend this one-liner

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

Warning: the list of videos, returned by Arrays.asList is immutable - you can't insert new values. If you need to modify it, wrap in new ArrayList<>(...).


Reference:

  1. Method Arrays#asList
  2. Constructor Gson
  3. Method Gson#fromJson (source json may be of type JsonElement, Reader, or String)
  4. Interface List
  5. JLS - Arrays
  6. JLS - Generic Interfaces
naXa stands with Ukraine
  • 35,493
  • 19
  • 190
  • 259
4

Be careful using the answer provide by @DevNG. Arrays.asList() returns internal implementation of ArrayList that doesn't implement some useful methods like add(), delete(), etc. If you call them an UnsupportedOperationException will be thrown. In order to get real ArrayList instance you need to write something like this:

List<Video> = new ArrayList<>(Arrays.asList(videoArray));
Bogdan Kornev
  • 101
  • 1
  • 5
  • wat? Arrays.asList returns a List interface, that provides add() and remove() as well! – Enrichman Aug 25 '16 at 21:54
  • 2
    @Enrichman: Arrays.asList() returns a fixed-size list backed by the specified array. This ArrayList implementation extends a class AbstractList and doesn't override the method remove(int index) from the base class. And if you look at the source code of the AbstractList.remove(int index) you would see it always thrown UnsupportedOperationException. The same is for add() method. – Bogdan Kornev Aug 27 '16 at 07:58
  • 1
    Wo, that's pretty ugly, I didn't know that. Thanks for pointing it out. :) – Enrichman Aug 27 '16 at 08:05