Android Gson 数据解析记录

Android Gson库泛型数据解析,定义数据类型为泛型时,直接使用Gson.fromJson(String, Type)并不能正确的将数据解析出来,而使用Retrofit的时候,定义到接口返回数据中,却能正确解析出来,这两者有什么区别,Retrofit又是怎么实现的?带着这个疑问来分析学习Gson

数据Model实体类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
// User
public class User {
public String name;
public int age;
public User(String name, int age) {
this.name = name;
this.age = age;
}
@Override
public String toString() {
return "User." + name + ",age=" + age;
}
}
// Dog
public class Dog {
public String name;
public String color;
public Dog(String name, String color) {
this.name = name;
this.color = color;
}
@Override
public String toString() {
return "Dog." + name;
}
}
// Room
public class Room<T, K> {
public T user;
public K dog;
public Room(T user, K dog) {
this.user = user;
this.dog = dog;
}
@Override
public String toString() {
return user.toString() + " & " + dog.toString();
}
}

Room 中定义了两个泛型成员变量 user, dog;

Gson.fromJson

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
private Room<User, Dog> getRoom(int age) {
User ur = new User("Trace", age);
Dog dg = new Dog("Andy", "white");
Room<User, Dog> room = new Room<>(ur, dg);
return room;
}
@Test
public void gsonTest() {
Gson gson = new Gson();
Room<User, Dog> room = getRoom(27);
String jsonStr = gson.toJson(room);
print(jsonStr);
// {"user":{"name":"Trace","age":27},"dog":{"name":"Andy","color":"white"}}
Room room2 = gson.fromJson(jsonStr, Room.class);
print(room2);
// {name=Trace, age=27.0} & {name=Andy, color=white}
print(room2.user.getClass());
// class com.google.gson.internal.LinkedTreeMap
print(room2.dog.getClass());
// class com.google.gson.internal.LinkedTreeMap
}

直接使用gson.fromJson,解析出来的user和dog,并不是UserDog数据类型,而是LinkedTreeMap

定义ParameterizedType

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
private Type getType(final Class rawClazz, final Class... typeArgs) {
return new ParameterizedType() {
@Override
public Type[] getActualTypeArguments() {
return typeArgs;
}
@Override
public Type getRawType() {
return rawClazz;
}
@Override
public Type getOwnerType() {
return null;
}
};
}
public void gsonTest() {
Gson gson = new Gson();
Room<User, Dog> room = getRoom(27);
print(room);
// User.Trace,age=27 & Dog.Andy
String jsonStr = gson.toJson(room);
print(jsonStr);
// {"user":{"name":"Trace","age":27},"dog":{"name":"Andy","color":"white"}}
Room<User, Dog> roomNew = gson.fromJson(jsonStr,
getType(Room.class, User.class, Dog.class));
print(roomNew);
// User.Trace,age=27 & Dog.Andy
}

使用ParameterizedType定义Type数据类型,实现getActualTypeArguments方法,指定数据类型TK,再使用gson.fromJson,正确的解析出来user和dog。

对比上面两种方法,实际是就是fromJson的第二个参数Type有区别,一个是Room.class,而另一个是Room.class

Type

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
@Test
public void gsonTest2() throws NoSuchMethodException {
Method m = What.class.getDeclaredMethod("getRoom");
Type returnType = m.getGenericReturnType();
print(returnType);
// x.com.appdemo.Room<x.com.appdemo.User, x.com.appdemo.Dog>
ParameterizedType actualType = (ParameterizedType) returnType;
//
Type[] args = actualType.getActualTypeArguments();
print(args[0]);
// class x.com.appdemo.User
print(args[1]);
// class x.com.appdemo.Dog
Room<User, Dog> room = getRoom(28);
Gson gson = new Gson();
String jsonStr = gson.toJson(room);
Room<User, Dog> room2 = gson.fromJson(jsonStr, returnType);
print(room2);
// User.Trace,age=28 & Dog.Andy
}
@Test
public void gsonTest3() throws NoSuchMethodException {
Method m = What.class.getDeclaredMethod("getRoomList");
Type returnType = m.getGenericReturnType();
print(returnType);
// java.util.List<x.com.appdemo.Room<x.com.appdemo.User, x.com.appdemo.Dog>>
ParameterizedType actualType = (ParameterizedType) returnType;
//
Type[] args = actualType.getActualTypeArguments();
print(args[0]);
// x.com.appdemo.Room<x.com.appdemo.User, x.com.appdemo.Dog>
args = ((ParameterizedType) args[0]).getActualTypeArguments();
print(args[0]);
// class x.com.appdemo.User
print(args[1]);
// class x.com.appdemo.Dog
}
@Test
public void gsonTest4() throws NoSuchMethodException {
Method m = What.class.getDeclaredMethod("getRoomArray");
Type returnType = m.getGenericReturnType();
print(returnType);
// x.com.appdemo.Room<x.com.appdemo.User, x.com.appdemo.Dog>[]
GenericArrayType actualType = (GenericArrayType) returnType;
//
Type eleType = actualType.getGenericComponentType();
print(eleType);
// x.com.appdemo.Room<x.com.appdemo.User, x.com.appdemo.Dog>
Type[] args = ((ParameterizedType) eleType).getActualTypeArguments();
print(args[0]);
// class x.com.appdemo.User
print(args[1]);
// class x.com.appdemo.Dog
}

接口Method定义

1
2
3
4
5
6
7
8
9
10
11
12
13
14
public class What {
public static Room<User, Dog> getRoom() {
return null;
}
public static List<Room<User, Dog>> getRoomList() {
return null;
}
public static Room<User, Dog>[] getRoomArray() {
return null;
}
}

What类中定义了三个方法,有返回值,和使用Retrofit的时候接口定义相似,在上面的三个test方法中,可以看出通过Method的定义,可以准确的得出泛型类的具体类型,所以Retrofit能够正确的解析出实体数据类。