This article discusses how to use GSON to deserialize JSON into a List using three questions.
Question 1
There are two classes:
class MyObj { int x;}class MyList { List
objList = new LinkedList<>();}
Can the following test pass?
@Test public void test1() { MyList myList = new Gson().fromJson("{objList:[]}", MyList.class); Assert.assertEquals(LinkedList.class, myList.objList.getClass()); }
Answer 1
The answer is: The test fails! The reason is that GSON does not know the specific type of objList, so he can only select the default ArrayList. For more detailed explanations, refer to this article and the source code of the ConstructorConstructor class. What should I do if I want GSON to create a consumer list instance? It is also simple, that is, to give the objList a more specific type:
class MyList { LinkedList
objList = new LinkedList<>();}
Question 2
Can the following test be passed?
@Test public void test2() { ArrayList
list = new Gson().fromJson("[{x:1}]", ArrayList.class); Assert.assertEquals(1, list.size()); Assert.assertEquals(MyObj.class, list.get(0).getClass()); }
Answer 2
Obviously, no. The fromJson method cannot infer from the "[{x: 1}]" parameter that the object in the number group is of the MyObj type, nor can it obtain this information from the ArrayList. class parameter. So change it to the following?
ArrayList
list = new Gson().fromJson("[{x:1}]", ArrayList
.class);
Even worse, compilation fails! Because Java generic is used
Wipe MethodTo put it bluntly, it is just the syntactic sugar provided by the compiler to the programmer. There is no ArrayList at all. Such a class. So how can GSON deserialize the generic object we want? The answer is, please help TypeToken:
@Test public void test3() { Type type = new TypeToken>() {}.getType(); ArrayList
list = new Gson().fromJson("[{x:1}]", type); Assert.assertEquals(1, list.size()); Assert.assertEquals(MyObj.class, list.get(0).getClass()); }
GSON provides
TypeTokenThis class helps us capture (capture) images like ArrayList Such generic information. The first line of code in test3 () creates
Anonymous internal classIn this way, the Java compiler will compile the generic information into this anonymous internal class, and then it can be
GetType ()Method
Reflection APIExtracted.
Question 3
If I want to write a general method that deserializes json into a List, is this method feasible?
public static
ArrayList
jsonToList(String json, Class
classOfT) { Type type = new TypeToken>() {}.getType(); return new Gson().fromJson(json, type); }
Can this test be passed?
@Test public void test4() { ArrayList
list = jsonToList("[{x:1}]", MyObj.class); Assert.assertEquals(1, list.size()); Assert.assertEquals(MyObj.class, list.get(0).getClass()); }
Answer 3
The answer is: The method is not feasible (although it can be compiled successfully), but the test is not passed! Or because Java genericErasureFor more information, see the question in stackoverflow. Is there a way to implement the general jsonToList () method? Some, but a little more complicated:
public static
ArrayList
jsonToList(String json, Class
classOfT) { Type type = new TypeToken>(){}.getType(); ArrayList
jsonObjs = new Gson().fromJson(json, type); ArrayList
listOfT = new ArrayList<>(); for (JsonObject jsonObj : jsonObjs) { listOfT.add(new Gson().fromJson(jsonObj, classOfT)); } return listOfT; }
The ArrayList is deserialized in two steps. And then convert JsonObject into classOfT objects one by one.