一、类型

Gson识别 4 种类型

  1. JsonPrimitive:其中包括基本类型的包装类和String类
  2. JsonObject:类似某个具体的类型,只不过以Json格式进行存储,因此通过对应的get可以获取以Json形式存在的那些属性。
  3. JsonArray:由JsonElement类型组成的数组类型,注意的是,由于是以Json格式存储的,所以JsonArray所存储的具体类型可以是混合的,为什么数组可以保存多个类型?因为存储的是Json格式的字符串。
  4. JsonNull:存放Null值。

使用

  • Gson重载了很多方法,因此Gson的使用基本都是围绕着fromJson(...)toJson(...)。看字面意思就知道一个从Json转化到具体的类型,一个用来转为成Json格式。

二、泛型集合类型

集合类型,用的最多的其实是List<>

  • 当我们有以下这个类型的时候,我们会发现里面有List<String>List<Integer>两个类型:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
package top.bingcu.gson;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

import java.util.List;

@Data
@AllArgsConstructor
@NoArgsConstructor
public class BasicInfo {
private List<String> strList;
private List<Integer> intList;
}

或许你可以说使用gson.fromJson(json, List<String>.class);gson.fromJson(json, List<Integer>.class);,但别忘了,Java的泛型可是采用了类型擦除机制的啊,List<String>.classList<Integer>.class最后都会被擦除成List.class这个类型。所以,Java泛型是java本身的缺点之一了。

因此,Gson为我们提供了一个TypeToken<T>类型,专门用来解决java泛型擦除的问题。即这样使用:

1
gson.fromJson(json, new TypeToken<List<String>>(){}.getType());
  • 注意:
  • 这里使用的是new TypeToken<T>(){},而不是new TypeToken<T>()。这里使用了匿名内部类,这样做的好处就是,我们传入了一个T类型,相当于我们定义了一个具体关于用户传进来的T类型参数的TypeToken类。
  • 说人话就是我们通过匿名内部类,将TypeToken<T>这个父类转化为具体的、不会被java进行类型擦除TypeToken<String>子类型,前者jvm会采取类型擦除行为,而后者规避了类型擦除。因为在子类继承父类的过程中,T类型已经从不确定类型变成了具体的String类型了。

三、嵌套类型

假如我们有这么一个类型:

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
package top.bingcu.gson;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;


@Data
@NoArgsConstructor
@AllArgsConstructor
public class Basic {
private BasicInfo basicInfo;
}

@Data
@NoArgsConstructor
@AllArgsConstructor
class BasicInfo {
private BasicInfoDetail basicInfoDetail
private List<String> strList;
private List<Integer> intList;
}

@Data
@NoArgsConstructor
@AllArgsConstructor
class BasicInfoDetail{
String datas;
}

由于Basic中包含BasicInfoBasicInfo又包含两个泛型集合类型和BasicInfoDetail类型,因此,Gson的toJson(...)fromJson(...)方法是无法自动识别这个如此复杂的自定义嵌套类型的。

所以我们要做的就是让Gson能够识别,需要使用到Gson提供的JsonDeserializer这个类了,我们可以实现这个类的deserialize方法使得Gson在解析Basic这个类的时候能够自动跑到我们写的JsonDeserializer实现类当中进行解析。

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
private static  class BasicInfoDeserializer implements JsonDeserializer<BasicInfo>{

/**
* 这样每次解析BasicInfo类型的时候,都会自动调用该方法
* 同时fromJson()方法返回的BasicInfo类型就都是我们所继承实现的这个方法所返回的对象
*/
@Override
public BasicInfo deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException {
Gson gson = new Gson();
JsonObject jsonObject = json.getAsJsonObject();


List<String> strList = gson.fromJson(jsonObject.get("strList").getAsString(), new TypeToken<List<String>>(){}.getType());
List<Integer> intList = gson.fromJson(jsonObject.get("intList").getAsString(), new TypeToken<List<Integer>>(){}.getType());

//设置需要返回的自定义BasicInfo类型
BasicInfo basicInfo = new BasicInfo();
basicInfo.setStrList(strList);
basicInfo.setIntList(intList);
//由于BasicInfoDetail类型里面只有一个String类型的属性,因此Gson自己能够解析的出来BasicInfoDetail类型
basicInfo.setBasicInfoDetail = gson.fromJson(jsonObject.get("basicInfoDetail").getAsString(), BasicInfoDetail.class);

return basicInfo;
}
}

这样BasicBasicInfoBasicInfoDetail三个类中的后两个就能正常解析了。然后就剩下Basic类型了

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
private static class BasicDeserializer implements JsonDeserializer<Basic>{

@Override
public Basic deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException {
JsonObject jsonObject = json.getAsJsonObject();
Gson gson = new Gson();

//这里的BasicInfo类型,由于上面已经手写过它的解析过程了,所以Gson能够识别到并且知道如何将它的属性和Json文本对应起来
BasicInfo basicInfo = gson.fromJson(jsonObject.get("basicInfo").getAsString(), BasicInfo.class);

Basic basic = new Basic();
basic.setBasicInfo(basicInfo);

return basic;
}
}

这样,我们就完成了一连环嵌套类的解析过程了,之后我们便可以直接解析Basic类了:

1
2
Gson gson = new Gson();
Basic basic = gson.fromJson(json, Basic.class);