72

I had been planning on using simpleXML for my serialization needs, but figured I would try JSON out, to learn something new.

This is the code I am using to try and serialize an ArrayList of test POJO's using Gson 1.7.1.

Note: I removed the Reader/Writers for a String "s" to simplify the code.

package test;

import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

import com.google.gson.Gson;

public class TestGsonSerialDeserialList {
    public static void main(String[] args) throws IOException{
        Gson gson = new Gson();

        //Make Serial 
        String s;
        List<TestObject> list = Collections.synchronizedList(new ArrayList<TestObject>() );
        list.add(new TestObject());
        list.add(new TestObject());

        s = gson.toJson(list, ArrayList.class);
        System.out.println(s);

        //Eat Serial
        List<TestObject> list2 = Collections.synchronizedList(gson.fromJson(s, ArrayList.class) );
        System.out.println(list2.get(0) );
        System.out.println(list2.get(1) );
    }
}

Here is the output I get:

[{"objectID":1,"i1":12345,"name":"abcdefg","s":["a","b","c"]},{"objectID":2,"i1":12345,"name":"abcdefg","s":["a","b","c"]}]
java.lang.Object@5c74c3aa
java.lang.Object@75d9fd51

To my newbie eyes this looks correct. Only, the DeSerialized list of objects contains basic Objects, rather then the TestObject's I serialized. Can anyone please explain to me what, if anything, I can do to make this work?

EDIT:

Corrected to test: Thanks to ColinD

package test;

import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.Reader;
import java.io.Writer;
import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

import com.google.gson.Gson;
import com.google.gson.reflect.TypeToken;

public class TestGsonSerialDeserialList {
    public static void main(String[] args) throws IOException{
        System.out.println("--- Serialize / Deserialize Started ---");
        String fileName = "json\\testList.json";

        Gson gson = new Gson();
        Type listOfTestObject = new TypeToken<List<TestObject>>(){}.getType();

        //Make Serial 
        Writer osWriter = new OutputStreamWriter( new FileOutputStream(fileName));
        List<TestObject> list = Collections.synchronizedList(new ArrayList<TestObject>() );
        list.add(new TestObject());
        list.add(new TestObject());
        list.add(new TestObject());
        list.add(new TestObject());
        gson.toJson(list, osWriter);
        osWriter.close();


        //Eat Serial
        Reader isReader = new InputStreamReader( new FileInputStream((fileName) ) );
        List<TestObject> list2 = Collections.synchronizedList(
            (List<TestObject>)gson.fromJson(isReader, listOfTestObject) 
        );
        isReader.close();
        System.out.println(list2.get(0) );
        System.out.println(list2.get(1) );
        System.out.println(list2.get(2) );
        System.out.println(list2.get(3) );
        System.out.println("--- Serialize / Deserialize Ended ---");
    }
}

output:

--- Serialize / Deserialize Started ---
ID#: 1, i1: 12345, name: abcdefg, s[]: [Ljava.lang.String;@95c083
ID#: 2, i1: 12345, name: abcdefg, s[]: [Ljava.lang.String;@6791d8c1
ID#: 3, i1: 12345, name: abcdefg, s[]: [Ljava.lang.String;@182d9c06
ID#: 4, i1: 12345, name: abcdefg, s[]: [Ljava.lang.String;@5a5e5a50
--- Serialize / Deserialize Ended ---

EDIT2:

I honestly don't know why, but when I replaced the simple String[] embedded in my TestObject with an ArrayList, it started serializing correctly.

--- Serialize / Deserialize Started ---
ID#: 1, i1: 12345, name: abcdefg, s[]: [a, b, c]
ID#: 2, i1: 12345, name: abcdefg, s[]: [a, b, c]
ID#: 3, i1: 12345, name: abcdefg, s[]: [a, b, c]
ID#: 4, i1: 12345, name: abcdefg, s[]: [a, b, c]
--- Serialize / Deserialize Ended ---
ROMANIA_engineer
  • 54,432
  • 29
  • 203
  • 199
RogueDeus
  • 847
  • 1
  • 8
  • 10
  • side note: Get rid of the Collections.synchronizedList() calls. You have a single-thread scenario, these calls only add overhead, nothing else – Sean Patrick Floyd Apr 28 '11 at 04:55
  • You are correct. They are there to make sure I can get it working. Once its working, I will remove them. This is purely for educational reasons. Once I get a good idea of Json serialization I will begin building for actual use. – RogueDeus Apr 28 '11 at 17:42
  • Having said that, can anyone point me to where I can figure out how to get the Object embedded array to deserialize with a TypeToken? – RogueDeus Apr 28 '11 at 17:43
  • Well, it seems that replacing the String[] with an ArrayList, fixed the problem. – RogueDeus Apr 28 '11 at 18:15

1 Answers1

172

You need to give Gson information on the specific generic type of List you're using (or any generic type you use with it). Particularly when deserializing JSON, it needs that information to be able to determine what type of object it should deserialize each array element to.

Type listOfTestObject = new TypeToken<List<TestObject>>(){}.getType();
String s = gson.toJson(list, listOfTestObject);
List<TestObject> list2 = gson.fromJson(s, listOfTestObject);

This is documented in the Gson user guide.

ColinD
  • 108,630
  • 30
  • 201
  • 202
  • I was afraid that I was not seeing something obvious. I have never used Type's before, and was confused at its use. You just cleared it up for me. Thank you very much. – RogueDeus Apr 28 '11 at 04:10
  • 1
    I may likely have another question regarding serialization of a Queue soon! Hope you don't mind. – RogueDeus Apr 28 '11 at 04:11
  • I was a bit quick there. It seems that I need to find a way to apply a TypeToken to the TestObject's String[]. – RogueDeus Apr 28 '11 at 04:47
  • @ColinD I can directly use this 'List list' to populate in android listview? custom adapter should implement serializable ? any help? – LOG_TAG Aug 09 '13 at 11:46
  • 2
    @ColinD What if `List` is nested in another class? How does the use of `Type` apply in that case to deserialize using something like `MyCustomClass obj = gson.fromJson(json, MyCustomClass.class)` – raffian Oct 08 '13 at 15:13
  • 1
    @raffian: Do you mean if `MyCustomClass` has a `List` field that needs to be deserialized? If so, there's no problem... Gson can see that the type of the field is `List` statically and deserialize the list based on that. – ColinD Oct 08 '13 at 19:49
  • @ColinD Yes, that's what I mean, a nested `List`. Does the same hold true for nested `HashMap`? I had some issues when deserializing `Boolean` and `Integer` values from the map, I suspect `Object` is the issue. I want to avoid boiler plate code to manually configure type transformers. Thanks for the tip. – raffian Oct 09 '13 at 14:01
  • This answer fixed half of my problem. But I also had to flip my column from `fetch = FetchType.LAZY` to `FetchType.EAGER` then my code started working. – cptully Oct 31 '19 at 19:26