探索Android开源框架 - 8. Gson使用及源码解析
2021-12-03 本文已影响0人
今阳说
- Gson 是 我们经常用来在 Java 对象和 JSON 数据之间进行映射的 库,今天我们就来分别讲一讲其使用和源码分析
使用详解
1. 基本的解析与生成
- Gson提供了fromJson() 和toJson() 两个直接用于解析和生成的方法,前者实现反序列化,后者实现了序列化
- 解析基本数据类型
val gson = Gson()
val i = gson.fromJson("100", Int::class.java) //100
val d = gson.fromJson("99.99", Double::class.java) //99.99
val b = gson.fromJson("true", Boolean::class.java) // true
val s = gson.fromJson("jin", String::class.java) // String
log("i=$i,d=$d,b=$b,s=$s")
- 生成基本数据类型
val gson = Gson()
val jsonI: String = gson.toJson(100) // 100
val jsonD: String = gson.toJson(99.99) // 100
val jsonB: String = gson.toJson(false) // false
val jsonS: String = gson.toJson("String") //"String"
log("jsonI=$jsonI,jsonD=$jsonD,jsonB=$jsonB,jsonS=$jsonS")
- 解析及生成自定义对象
//先定义一个数据模型类,这里需要注意的一点是在方法内部定义的类gson解析和生成都是null,所以应该放到类或单独的文件中定义
data class UserInfo(var name: String?, var age: Int?, var emailAddress: String? )
//创建自定义对象
val user = UserInfo(name = "222", age = 18, "xxx@163.com")
log("user=${user}")
//转为json字符串
val gson = Gson()
val userStr = gson.toJson(user)
log("userStr:$userStr")
//从字符串转为自定义对象
val user2: UserInfo? = gson.fromJson(userStr, UserInfo::class.java)
log("user2=${user2}")
2. 属性重命名
@SerializedName 注解的使用
- @SerializedName接收两个参数,value字符串对属性重命名及alternate数组为属性提供多个备选属性名
- toJson后的字符串中的属性名会以value中的值为准
- 为字段提供备选属性名,当多种情况同时出时,以最后一个出现的值为准
- 为数据模型类添加注解
data class UserInfo(
@SerializedName(value = "name", alternate = ["user_name"]) var name: String?,
@SerializedName("age", alternate = ["user_age", "u_age", "Age"]) var age: Int?,
@SerializedName("emailAddress") var emailAddress: String? = null,
)
- 解析与生成json字符串
val user3: UserInfo? =
gson.fromJson("{\"user_age\":18,\"user_name\":\"333\"}", UserInfo::class.java)
log("user3=$user3")
val user4: UserInfo? =
gson.fromJson("{\"u_age\":18,\"user_name\":\"444\"}", UserInfo::class.java)
log("user4=$user4")
val user5: UserInfo? = gson.fromJson(
"{\"Age\":18,\"user_age\":19,\"u_age\":20,\"user_name\":\"555\"}",
UserInfo::class.java
)
log("user5=$user5")
POJO与JSON的字段映射规则
- GsonBuilder提供了setFieldNamingPolicy和setFieldNamingStrategy 两个方法;
- setFieldNamingPolicy方法与FieldNamingPolicy枚举配合使用,提供了如下几种选择
val gson = GsonBuilder()
// .setFieldNamingPolicy(FieldNamingPolicy.IDENTITY)//emailAddress
// .setFieldNamingPolicy(FieldNamingPolicy.LOWER_CASE_WITH_DASHES)//email-address
// .setFieldNamingPolicy(FieldNamingPolicy.LOWER_CASE_WITH_UNDERSCORES)//email_address
// .setFieldNamingPolicy(FieldNamingPolicy.UPPER_CAMEL_CASE)//EmailAddress
.setFieldNamingPolicy(FieldNamingPolicy.UPPER_CAMEL_CASE_WITH_SPACES)//Email Address
.create()
val user = UserInfo(name = "222", age = 18, "xxx@163.com")
log("setFieldNamingPolicy:${gson.toJson(UserInfo3())}")
- setFieldNamingStrategy与Gson提供的FieldNamingStrategy接口配合使用 实现自己的规则
//1. 实现FieldNamingStrategy接口,定义自己的规则
class FieldStrategy {
/**
* 采用全部大写的形式
*/
class AllUpperCaseStrategy : FieldNamingStrategy {
override fun translateName(f: Field): String {
return f.name.uppercase(Locale.getDefault())
}
}
/**
* 添加前置 和 后置 注解
*/
class GsonKeyValueCaseStrategy : FieldNamingStrategy {
override fun translateName(f: Field): String {
val gkv: GsonKeyValue? = f.getAnnotation(GsonKeyValue::class.java)
return if (gkv != null) {
if (gkv.value.isNotEmpty()) {
gkv.prefix + gkv.value + gkv.suffix
} else {
gkv.prefix + f.name + gkv.suffix
}
} else {
f.name
}
}
}
}
//2.使用
val gson = GsonBuilder()
.setFieldNamingStrategy(FieldStrategy.AllUpperCaseStrategy())
.setFieldNamingStrategy(FieldStrategy.GsonKeyValueCaseStrategy())
.create()
val user = UserInfo(name = "222", age = 18, "xxx@163.com")
log("setFieldNamingStrategy:${gson.toJson(user)}")
- @SerializedName注解拥有最高优先级,在加有@SerializedName注解的字段上FieldNamingStrategy不生效
使用GsonBuilder
- 上面我们没有通过Gson()构造方法来创建Gson实例,而是使用了GsonBuilder,下面介绍一些其方法
val gsonDIY = GsonBuilder()
//序列化null,Gson在默认情况下是不动导出值null的键的
.serializeNulls()
// 设置日期时间格式,另有2个重载方法
// 在序列化和反序化时均生效
.setDateFormat("yyyy-MM-dd")
// 禁此序列化内部类
.disableInnerClassSerialization()
//生成不可执行的Json, 其实就是多了 )]}' 这4个字符
.generateNonExecutableJson()
//禁止转义html标签
.disableHtmlEscaping()
//格式化输出
.setPrettyPrinting()
.create() //生成配置好的Gson
//使用
val user8 = UserInfo("888", 18)
val user8Str = gsonDIY.toJson(user8)
log("user8 toJson:${user8Str}")
log("fromJson user8Str:${gsonDIY.fromJson(user8Str, UserInfo::class.java)}")
泛型
val gson = Gson()
val jsonArray = gson.toJson(arrayOf(user2, user3, user4, user5))
val userArr = gson.fromJson(jsonArray, Array<UserInfo>::class.java)
log("userArr=${gson.toJson(userArr)}")
val userList: List<UserInfo> = gson.fromJson(jsonArray, List::class.java) as List<UserInfo>
log("userList=$userList")
//Java泛型使用时要注意泛型擦除,Gson为我们提供了TypeToken来实现对泛型的支持
val userList2: List<UserInfo?>? =
gson.fromJson(jsonArray, object : TypeToken<List<UserInfo?>?>() {}.type)
log("userList2=$userList2")
泛型的封装
- 但是每次解析泛型都要写TypeToken就很麻烦,所以我们可以在工具类中做一些简单的封装
fun getListType(type: Type): Type {
return TypeToken.getParameterized(MutableList::class.java, type).type
}
fun getSetType(type: Type): Type {
return TypeToken.getParameterized(MutableSet::class.java, type).type
}
fun getMapType(keyType: Type, valueType: Type): Type {
return TypeToken.getParameterized(MutableMap::class.java, keyType, valueType).type
}
fun getArrayType(type: Type): Type {
return TypeToken.getArray(type).type
}
fun getType(rawType: Type, vararg typeArguments: Type): Type {
return TypeToken.getParameterized(rawType, *typeArguments).type
}
- 或者涉及到实际业务,比如网络数据的解析,还可以像下面这样再进一步封装一下
/**
* 解析data是object的情况
*/
fun <T> fromJson2Object(json: String?, clazz: Class<T>): BaseHttpResponse<T>? {
val type: Type = getType(BaseHttpResponse::class.java, clazz)
return fromJson(json, type)
}
/**
* 解析data是array的情况
*/
fun <T> fromJson2Array(json: String?, clazz: Class<T>): BaseHttpResponse<MutableList<T?>?>? {
// 生成List<T> 中的 List<T>
val listType: Type = getListType(clazz)
// 根据List<T>生成完整的BaseHttpResponse<List<T>>
val type: Type = getType(BaseHttpResponse::class.java, listType)
return fromJson(json, type)
}
/**
* 解析data是Map的情况
*/
fun <K, T> fromJson2Map(json: String?, clazz1: Class<K>, clazz2: Class<T>): BaseHttpResponse<MutableMap<K?, T?>?>? {
// 生成BaseHttpResponse<Map<K,T>> 中的 Map<K,T>
val mapType: Type = getMapType(clazz1, clazz2)
// 根据Map<K,T>生成完整的BaseHttpResponse<Map<K,T>>
val type: Type = getType(BaseHttpResponse::class.java, mapType)
return fromJson(json, type)
}
- 上面封装的使用测试如下
//网络数据的基类
data class BaseHttpResponse<T>(
@SerializedName(value = "code", alternate = ["Status", "status"]) var code: Int? = null,
@SerializedName(value = "message", alternate = ["Msg", "msg"]) var message: String? = null,
@SerializedName(value = "data", alternate = ["Data"]) var data: T? = null
)
//对BaseHttpResponse<UserInfo3>的解析
val baseHttpResponse1=BaseHttpResponse(111,"aaa",UserInfo3("ljy",18))
val strResponse1:String=GsonUtils.toJson(baseHttpResponse1)
log("fromJsonObject:${GsonUtils.fromJson2Object(strResponse1,UserInfo3::class.java)}")
//对List<UserInfo3>的解析
val list=mutableListOf(UserInfo3("ljy",18),UserInfo3("qwer",19))
log("fromJson(json,Type):${GsonUtils.fromJson<List<UserInfo3>>(GsonUtils.toJson(list),GsonUtils.getListType(UserInfo3::class.java))}")
//对BaseHttpResponse<List<UserInfo3>>的解析
val baseHttpResponse2=BaseHttpResponse<List<UserInfo3>>(111,"aaa",list)
val strResponse2:String=GsonUtils.toJson(baseHttpResponse2)
log("fromJsonArray:${GsonUtils.fromJson2Array(strResponse2,UserInfo3::class.java)}")
//对Map<String,UserInfo3>的解析
val map= mutableMapOf("key1" to UserInfo3("ljy",18),"key2" to UserInfo3("qwer",19))
log("fromJson(json,Type):${GsonUtils.fromJson<Map<String,UserInfo3>>(GsonUtils.toJson(map),GsonUtils.getMapType(String::class.java,UserInfo3::class.java))}")
//对BaseHttpResponse<Map<String,UserInfo3>>的解析
val baseHttpResponse3=BaseHttpResponse<List<UserInfo3>>(111,"aaa",map)
val strResponse3:String=GsonUtils.toJson(baseHttpResponse3)
log("fromJsonMap:${GsonUtils.fromJson2Map(strResponse3,String::class.java,UserInfo3::class.java)}")
Gson的序列化、反序列化
Gson的流式反序列化
- 手动的方式: 使用stream包下的JsonReader类来手动实现反序列化,和Android中使用pull解析XML是比较类似的
val user6 = UserInfo(null, null, null, null)
val reader = JsonReader(StringReader(userStr))
reader.beginObject()
while (reader.hasNext()) {
when (reader.nextName()) {
"name" ->
user6.name = reader.nextString()
"age" ->
user6.age = reader.nextInt()
"emailAddress" ->
user6.emailAddress = reader.nextString()
"temp" ->
user6.temp = reader.nextString()
"date" ->
user6.date = Date(reader.nextString())
}
}
reader.endObject()
log("user6=$user6")
- 自动方式最终都是通过JsonReader来实现的,如果第一个参数是String类型,那么Gson会创建一个StringReader转换成流操作,源码如下:
public <T> T fromJson(String json, Type typeOfT) throws JsonSyntaxException {
if (json == null) {
return null;
}
StringReader reader = new StringReader(json);
T target = (T) fromJson(reader, typeOfT);
return target;
}
Gson的流式序列化
- 手动
val user7 = UserInfo("777", 17, "7777@qq.com")
// val writer = JsonWriter(OutputStreamWriter(System.out))
val stringWriter = StringWriter()
val writer = JsonWriter(stringWriter)
writer.beginObject()
.name("name").value(user7.name)
.name("age").value(user7.age)
.name("emailAddress").nullValue()
.endObject()
writer.flush()
log("user7=$stringWriter")
- 自动
// PrintStream(System.out) 、StringBuilder、StringBuffer和*Writer都实现了Appendable接口。
gson.toJson(user,System.out)
val str1 = gson.toJson(user)
//toJson源码如下:
//public String toJson(Object src, Type typeOfSrc) {
// StringWriter writer = new StringWriter();
// toJson(src, typeOfSrc, writer);
// return writer.toString();
//}
字段过滤的几种方法
1. @Expose注解
- 基于@Expose注解:需要导出的字段上加上@Expose 注解,不导出的字段不加
data class UserInfo(
@Expose //@Expose提供了两个属性,且默认值都为true
var name: String?,
@Expose(deserialize = true,serialize = true) //序列化和反序列化都都生效
var age: Int?,
@Expose(deserialize = true,serialize = false) //反序列化时生效
var emailAddress: String? = null,
@Expose(deserialize = false,serialize = true) //序列化时生效
var date: Date? = Date(),
@Expose(deserialize = false,serialize = false) // 和不写注解一样
var temp: String? = "没啥用的temp"
)
- 在使用Gson时也要用GsonBuilder调用excludeFieldsWithoutExposeAnnotation方法使其支持@Expose
val gson3 = GsonBuilder()
.excludeFieldsWithoutExposeAnnotation()
.create()
gson3.toJson(user8)
log("user8 toJson:${gson3.toJson(user8)}")
2. 基于版本
- Gson在对基于版本的字段导出提供了两个注解 @Since 和 @Until,都接收一个Double值
data class UserInfo2(
var name: String?,
@Since(3.0)
var age: Int?,
@Until(6.0)
var emailAddress: String? = null,
)
- 配合GsonBuilder.setVersion(Double)使用,当前版本(GsonBuilder中设置的版本) 大于等于Since的值时该字段导出,小于Until的值时该该字段导出
val user9 = UserInfo2("999", 19, "9999@qq.com")
log("user9 version 1.0:" + GsonBuilder().setVersion(1.0).create().toJson(user9))
log("user9 version 4.0:" + GsonBuilder().setVersion(4.0).create().toJson(user9))
log("user9 version 9.0:" + GsonBuilder().setVersion(9.0).create().toJson(user9))
val user9Str = "{\"age\":19,\"emailAddress\":\"9999@qq.com\",\"name\":\"999\"}"
log("user9Str version 1.0:" + GsonBuilder().setVersion(1.0).create().fromJson(user9Str, UserInfo2::class.java))
log("user9Str version 4.0:" + GsonBuilder().setVersion(4.0).create().fromJson(user9Str, UserInfo2::class.java))
log("user9Str version 9.0:" + GsonBuilder().setVersion(9.0).create().fromJson(user9Str, UserInfo2::class.java))
3. 基于访问修饰符
- 基于public、static 、final、private、protected这些访问修饰符,通过GsonBuilder().excludeFieldsWithModifiers()方法进行控制
//用不同的修饰符修饰模型类Test的字段
public class Test {
final String finalField = "final";
static String staticField = "static";
public String publicField = "public";
protected String protectedField = "protected";
String defaultField = "default";
boolean man=true;
private String privateField = "private";
}
//排除final,static,private修饰的字段
val gson4 = GsonBuilder()
.excludeFieldsWithModifiers(Modifier.FINAL, Modifier.STATIC, Modifier.PRIVATE)
.create()
log(gson4.toJson(Test()))
4. 基于策略(自定义规则)
- GsonBuilder的addSerializationExclusionStrategy , addDeserializationExclusionStrategy 两个方法分别针对序列化和反序化
- 两个方法入参传入ExclusionStrategy接口的实现类,在其中实现自己的规则
val gson5 = GsonBuilder()
.addSerializationExclusionStrategy(object : ExclusionStrategy {
override fun shouldSkipField(f: FieldAttributes): Boolean {
// 这里作判断,决定要不要排除该字段,return true为排除
if ("emailAddress" == f.name) return true //按字段名排除
val expose = f.getAnnotation(Expose::class.java)
return expose != null && !expose.deserialize //按注解排除:
}
override fun shouldSkipClass(clazz: Class<*>): Boolean {
// 直接排除某个类 ,return true为排除,例如排除Boolean.kt和Boolean.java
return clazz == Boolean::class || clazz == Boolean::class.java
}
})
.create()
log("UserInfo3:${gson5.toJson(UserInfo3())}")
log("Test:${gson5.toJson(Test())}")
TypeAdapter
- 用于接管某种类型的序列化和反序列化过程,包含两个注要方法 write(JsonWriter,T) 和 read(JsonReader),其它的方法都是final方法并最终调用这两个抽象方法。
- 自定义UserInfoTypeAdapter
class UserInfoTypeAdapter : TypeAdapter<UserInfo3?>() {
@Throws(IOException::class)
override fun write(out: JsonWriter?, value: UserInfo3?) {
out?.run {
value?.let {
beginObject()
name("name").value(it.name)
name("age").value(it.age)
name("emailAddress").value(it.emailAddress)
endObject()
}
}
}
@Throws(IOException::class)
override fun read(`in`: JsonReader): UserInfo3 {
val user = UserInfo3()
`in`.beginObject()
while (`in`.hasNext()) {
when (`in`.nextName()) {
"name" -> user.name = `in`.nextString()
"age" -> user.age = `in`.nextInt()
"email", "email_address", "emailAddress" -> user.emailAddress =
`in`.nextString()
}
}
`in`.endObject()
return user
}
}
- 为UserInfo3注册UserInfoTypeAdapter
val gson8 = GsonBuilder()
.registerTypeAdapter(UserInfo3::class.java, UserInfoTypeAdapter())
.create()
log(gson8.toJson(UserInfo3()))
log(gson8.fromJson("{\"name\":\"ljy\",\"age\":20,\"email_address\":\"xx@qq.com\",\"email\":\"qqq@qq.com\"}", UserInfo3::class.java))
JsonSerializer与JsonDeserializer
- 但是如果想只接管序列化或反序列化其中之一呢?只接管序列化的过程就用 JsonSerializer ,只接管反序列化的过程就用 JsonDeserializer
- 例如接口返回的数据,某个字段是int型,如果有些情况下给你返了个空字符串怎么办
- 用TypeAdapter实现
class NumTypeAdapter : TypeAdapter<Number>() {
override fun write(out: JsonWriter, value: Number) {
log("numTypeAdapter.write:$value")
out.value(value.toString())
}
override fun read(`in`: JsonReader): Number {
return try {
val str = `in`.nextString()
log("numTypeAdapter.read:$str")
if (str == null || str.isEmpty()) {
return -1
}
NumberFormat.getInstance().parse(str) ?: -1
} catch (e: Exception) {
log("e:$e")
-1
}
}
}
- 用JsonSerializer与JsonDeserializer实现
class NumJsonSerializer : JsonSerializer<Number> {
override fun serialize(
src: Number?,
typeOfSrc: Type?,
context: JsonSerializationContext?
): JsonElement {
log("typeOfSrc:$typeOfSrc")
return JsonPrimitive(src.toString())
}
}
class NumJsonDeserializer : JsonDeserializer<Number> {
override fun deserialize(
json: JsonElement?,
typeOfT: Type?,
context: JsonDeserializationContext?
): Number {
return try {
log("typeOfT:$typeOfT")
json?.asNumber ?: -1
} catch (e: Exception) {
log("e:${e}")
-1
}
}
}
- 使用测试
val gson9 = GsonBuilder()
.registerTypeAdapter(Number::class.java, NumTypeAdapter())
.registerTypeHierarchyAdapter(Number::class.java, NumJsonSerializer())
.registerTypeHierarchyAdapter(Number::class.java, NumJsonDeserializer())
.create()
log(gson9.toJson(100, Number::class.java))
log(gson9.toJson(6.66, Number::class.java))
log(gson9.toJson(111111111111111111, Number::class.java))
log(gson9.fromJson("\"\"", Number::class.java))
log(gson9.fromJson("", Number::class.java))
log(gson9.fromJson("88.88", Number::class.java))
log(gson9.fromJson("55", Number::class.java))
log(gson9.fromJson("111111111111111111", Number::class.java))
log(gson9.toJson(100, Int::class.java))
log(gson9.toJson(6.66, Double::class.java))
log(gson9.toJson(111111111111111111, Long::class.java))
log(gson9.fromJson("\"\"", Number::class.java))
log(gson9.fromJson("", Double::class.java))
log(gson9.fromJson("88.88", Double::class.java))
log(gson9.fromJson("55", Int::class.java))
log(gson9.fromJson("111111111111111111", Long::class.java))
- registerTypeAdapter与registerTypeHierarchyAdapter的区别:
- registerTypeAdapter:支持泛型,不支持继承
- registerTypeHierarchyAdapter:不支持泛型,支持继承
- TypeAdapter与 JsonSerializer、JsonDeserializer对比,TypeAdapter效率高,内存占用小,支持Stream API
实战
- 服务器返回的数据中data字段类型不固定,比如请求成功data是一个List,不成功的时候是String类型,这样前端在使用泛型解析的时候,怎么去处理呢?
val gson11 = GsonBuilder().registerTypeHierarchyAdapter(
MutableList::class.java,
JsonDeserializer { json, typeOfT, context ->
if (json.isJsonArray) {
log("isJsonArray")
val array = json.asJsonArray
val itemType: Type =
(typeOfT as ParameterizedType).actualTypeArguments[0]
val list: MutableList<Any?> = mutableListOf()
for (i in 0 until array.size()) {
val element = array[i]
val item = context.deserialize<Any>(element, itemType)
list.add(item)
}
list
} else {
log("返回空List")
Collections.EMPTY_LIST
}
}).create()
log(gson11.toJson(listOf(UserInfo3())))
val type = object : TypeToken<List<UserInfo3?>?>() {}.type
log(gson11.fromJson("[{\"age\":20,\"emailAddress\":\"xx@qq.com\",\"height\":180,\"man\":true,\"name\":\"ljy\"}]", type))
log(gson11.fromJson("{}", type))
log(gson11.fromJson("暂无数据", type))
TypeAdapterFactory
- 用于创建TypeAdapter的工厂类,通过对比Type,确定有没有对应的TypeAdapter,没有就返回null,与GsonBuilder.registerTypeAdapterFactory配合使用
- 比如根据当为null时,根据泛型是String则返回“”,是List则返回空list
class GsonDefaultAdapterFactory: TypeAdapterFactory {
override fun <T : Any> create(gson: Gson, type: TypeToken<T>): TypeAdapter<T>? {
if (type.type == String::class.java) {
return createStringAdapter()
}
if (type.rawType == List::class.java || type.rawType == Collection::class.java) {
return createCollectionAdapter(type, gson)
}
return null
}
/**
* null替换成空List
*/
private fun <T : Any> createCollectionAdapter(
type: TypeToken<T>,
gson: Gson
): TypeAdapter<T>? {
val rawType = type.rawType
if (!Collection::class.java.isAssignableFrom(rawType)) {
return null
}
val elementType: Type = `$Gson$Types`.getCollectionElementType(type.type, rawType)
val elementTypeAdapter: TypeAdapter<Any> =
gson.getAdapter(TypeToken.get(elementType)) as TypeAdapter<Any>
return object : TypeAdapter<Collection<Any>>() {
override fun write(writer: JsonWriter, value: Collection<Any>?) {
writer.beginArray()
value?.forEach {
elementTypeAdapter.write(writer, it)
}
writer.endArray()
}
override fun read(reader: JsonReader): Collection<Any> {
val list = mutableListOf<Any>()
// null替换为""
if (reader.peek() == JsonToken.NULL) {
reader.nextNull()
return list
}
reader.beginArray()
while (reader.hasNext()) {
val element = elementTypeAdapter.read(reader)
list.add(element)
}
reader.endArray()
return list
}
} as TypeAdapter<T>
}
/**
* null 替换成空字符串
*/
private fun <T : Any> createStringAdapter(): TypeAdapter<T> {
return object : TypeAdapter<String>() {
override fun write(writer: JsonWriter, value: String?) {
if (value == null) {
writer.value("")
} else {
writer.value(value)
}
}
override fun read(reader: JsonReader): String {
// null替换为""
if (reader.peek() == JsonToken.NULL) {
reader.nextNull()
return ""
}
return reader.nextString()
}
} as TypeAdapter<T>
}
}
//使用
val gson10 = GsonBuilder()
.registerTypeAdapterFactory(GsonDefaultAdapterFactory())
.create()
@JsonAdapter注解
- 用在自定义模型类上,接收一个参数,且参数类型必须是TypeAdapter,TypeAdapterFactory,JsonSerializer或JsonDeserializer其中之一
// @JsonAdapter(NumJsonSerializer::class)
// @JsonAdapter(NumJsonDeserializer::class)
// @JsonAdapter(NumTypeAdapter::class)
@JsonAdapter(KotlinAdapterFactory2::class)
data class UserInfo5(
var name: String = "ljy",
private var email: String? = "xxx@qq.com",
private val mobile: String? = "12315",
)
- 使用时就不用再使用 GsonBuilder去注册UserTypeAdapter了
log("UserInfo5:${Gson().toJson(UserInfo5())}")
源码解析
- 使用时我们是从fromJson(反序列化) and toJson(序列化)这两个最基础的方法开始,那么我们来点进去看看他们是如何实现的
fromJson方法
- fromJson有多个重载方法,最终都会调用到fromJson(JsonReader reader, Type typeOfT)
public <T> T fromJson(String json, Class<T> classOfT) throws JsonSyntaxException {
//Class<T>转为Type
Object object = fromJson(json, (Type) classOfT);
return Primitives.wrap(classOfT).cast(object);
}
public <T> T fromJson(String json, Type typeOfT) throws JsonSyntaxException {
if (json == null) {
return null;
}
//将String包装为StringReader
StringReader reader = new StringReader(json);
T target = (T) fromJson(reader, typeOfT);
return target;
}
public <T> T fromJson(Reader json, Type typeOfT) throws JsonIOException, JsonSyntaxException {
//将Reader包装为JsonReader
JsonReader jsonReader = newJsonReader(json);
T object = (T) fromJson(jsonReader, typeOfT);
assertFullConsumption(object, jsonReader);
return object;
}
public <T> T fromJson(JsonReader reader, Type typeOfT) throws JsonIOException, JsonSyntaxException {
boolean isEmpty = true;
boolean oldLenient = reader.isLenient();
reader.setLenient(true);
try {
reader.peek();
isEmpty = false;
TypeToken<T> typeToken = (TypeToken<T>) TypeToken.get(typeOfT);
//获取TypeAdapter
TypeAdapter<T> typeAdapter = getAdapter(typeToken);
T object = typeAdapter.read(reader);
return object;
} catch //。。。省略很多异常处理
} finally {
reader.setLenient(oldLenient);
}
}
- 从上面代码可以看到最终调用了getAdapter来根据typeToken获取TypeAdapter,再通过TypeAdapter.read方法最终反序列化数据,上面的使用详解中我们有介绍了如何自定义TypeAdapter,所以对read方法也就不默生了;
getAdapter方法
- 那么来看一下getAdapter方法是如何实现的
public <T> TypeAdapter<T> getAdapter(TypeToken<T> type) {
//先从缓存ConcurrentHashMap<TypeToken<?>, TypeAdapter<?>> typeTokenCache中取
TypeAdapter<?> cached = typeTokenCache.get(type == null ? NULL_KEY_SURROGATE : type);
if (cached != null) {
return (TypeAdapter<T>) cached;
}
//再从ThreadLocal<Map<TypeToken<?>, FutureTypeAdapter<?>>> calls 中取
Map<TypeToken<?>, FutureTypeAdapter<?>> threadCalls = calls.get();
boolean requiresThreadLocalCleanup = false;
if (threadCalls == null) {
threadCalls = new HashMap<TypeToken<?>, FutureTypeAdapter<?>>();
calls.set(threadCalls);
requiresThreadLocalCleanup = true;
}
// the key and value type parameters always agree
FutureTypeAdapter<T> ongoingCall = (FutureTypeAdapter<T>) threadCalls.get(type);
if (ongoingCall != null) {
return ongoingCall;
}
try {
FutureTypeAdapter<T> call = new FutureTypeAdapter<T>();
threadCalls.put(type, call);
//缓存map和ThreadLocal中都没有,则循环List<TypeAdapterFactory> factories 集合
for (TypeAdapterFactory factory : factories) {
TypeAdapter<T> candidate = factory.create(this, type);
if (candidate != null) {
call.setDelegate(candidate);
typeTokenCache.put(type, candidate);
return candidate;
}
}
throw new IllegalArgumentException("GSON (" + GsonBuildConfig.VERSION + ") cannot handle " + type);
} finally {
threadCalls.remove(type);
if (requiresThreadLocalCleanup) {
calls.remove();
}
}
}
- 其中通过ThreadLocal缓存TypeAdapter对象,不同的线程使用缓存来解析的时候互不影响
- 通过上面代码可以看到最终是在List<TypeAdapterFactory> factories 集合中获取到TypeAdapter的,factories里面都有啥呢,我们来看看Gson构造方法中是如何初始化的
Gson的构造方法
public Gson() {
this(Excluder.DEFAULT, FieldNamingPolicy.IDENTITY,
Collections.<Type, InstanceCreator<?>>emptyMap(), DEFAULT_SERIALIZE_NULLS,
DEFAULT_COMPLEX_MAP_KEYS, DEFAULT_JSON_NON_EXECUTABLE, DEFAULT_ESCAPE_HTML,
DEFAULT_PRETTY_PRINT, DEFAULT_LENIENT, DEFAULT_SPECIALIZE_FLOAT_VALUES,
LongSerializationPolicy.DEFAULT, null, DateFormat.DEFAULT, DateFormat.DEFAULT,
Collections.<TypeAdapterFactory>emptyList(), Collections.<TypeAdapterFactory>emptyList(),
Collections.<TypeAdapterFactory>emptyList());
}
Gson(。。。) {
。。。
List<TypeAdapterFactory> factories = new ArrayList<TypeAdapterFactory>();
factories.add(TypeAdapters.JSON_ELEMENT_FACTORY);
factories.add(ObjectTypeAdapter.FACTORY);
factories.add(excluder);
factories.addAll(factoriesToBeAdded);
factories.add(TypeAdapters.STRING_FACTORY);
factories.add(TypeAdapters.INTEGER_FACTORY);
factories.add(TypeAdapters.BOOLEAN_FACTORY);
factories.add(TypeAdapters.BYTE_FACTORY);
factories.add(TypeAdapters.SHORT_FACTORY);
factories.add。。。//太多了
this.jsonAdapterFactory = new JsonAdapterAnnotationTypeAdapterFactory(constructorConstructor);
factories.add(jsonAdapterFactory);
factories.add(TypeAdapters.ENUM_FACTORY);
factories.add(new ReflectiveTypeAdapterFactory(
constructorConstructor, fieldNamingStrategy, excluder, jsonAdapterFactory));
this.factories = Collections.unmodifiableList(factories);
}
- 可以看到factories中添加了很多预制的TypeAdapterFactory,我们拿出其中的STRING_FACTORY看一下是如何实现的
public static final TypeAdapterFactory STRING_FACTORY = newFactory(String.class, STRING);
public static final TypeAdapter<String> STRING = new TypeAdapter<String>() {
@Override
public String read(JsonReader in) throws IOException {
JsonToken peek = in.peek();
if (peek == JsonToken.NULL) {
in.nextNull();
return null;
}
/* coerce booleans to strings for backwards compatibility */
if (peek == JsonToken.BOOLEAN) {
return Boolean.toString(in.nextBoolean());
}
return in.nextString();
}
@Override
public void write(JsonWriter out, String value) throws IOException {
out.value(value);
}
};
- 可以看到其调用了newFactory方法, 其实就是判断一下typeToken.getRawType() == type,就直接返回了入参的TypeAdapter STRING
public static <TT> TypeAdapterFactory newFactory(
final Class<TT> type, final TypeAdapter<TT> typeAdapter) {
return new TypeAdapterFactory() {
@SuppressWarnings("unchecked") // we use a runtime check to make sure the 'T's equal
@Override public <T> TypeAdapter<T> create(Gson gson, TypeToken<T> typeToken) {
return typeToken.getRawType() == type ? (TypeAdapter<T>) typeAdapter : null;
}
@Override public String toString() {
return "Factory[type=" + type.getName() + ",adapter=" + typeAdapter + "]";
}
};
}
- 再回到getAdapter方法,循环factories中调用了factory.create方法,其实就是上面newFactory中的实现的TypeAdapterFactory的create方法
- 需要注意的一点是Gson初始化factories时的顺序,首先是各种常用的基础类的TypeAdapterFactory,最后几行中添加JsonAdapterAnnotationTypeAdapterFactory对象在ReflectiveTypeAdapterFactory对象之前,如果对实体类使用了@JsonAdapter且指定的适配器存在那么就会返回@JsonAdapter里指定的适配器而不返回ReflectiveTypeAdapterFactory创建的,这样我们就可以自己接管后面的解析过程了
JsonAdapterAnnotationTypeAdapterFactory
- JsonAdapterAnnotationTypeAdapterFactory的create方法如下
public <T> TypeAdapter<T> create(Gson gson, TypeToken<T> targetType) {
Class<? super T> rawType = targetType.getRawType();
JsonAdapter annotation = rawType.getAnnotation(JsonAdapter.class);
if (annotation == null) {
return null;
}
return (TypeAdapter<T>) getTypeAdapter(constructorConstructor, gson, targetType, annotation);
}
ReflectiveTypeAdapterFactory
- 没有使用@JsonAdapter注解的返回ReflectiveTypeAdapterFactory实例,我们看看它的create方法
@Override public <T> TypeAdapter<T> create(Gson gson, final TypeToken<T> type) {
Class<? super T> raw = type.getRawType();
if (!Object.class.isAssignableFrom(raw)) {
return null; // it's a primitive!
}
ObjectConstructor<T> constructor = constructorConstructor.get(type);
return new Adapter<T>(constructor, getBoundFields(gson, type, raw));
}
- create中主要是调用getBoundFields方法,将实体类中需要解析的字段添加一个集合里,在反序列化时进行赋值
private Map<String, BoundField> getBoundFields(Gson context, TypeToken<?> type, Class<?> raw) {
Map<String, BoundField> result = new LinkedHashMap<String, BoundField>();
if (raw.isInterface()) {
return result;
}
Type declaredType = type.getType();
while (raw != Object.class) {
//得到实体类所有的字段
Field[] fields = raw.getDeclaredFields();
for (Field field : fields) {
//字段是否参与反序列化或者序列化过程
boolean serialize = excludeField(field, true);
boolean deserialize = excludeField(field, false);
if (!serialize && !deserialize) {
continue;
}
accessor.makeAccessible(field);
Type fieldType = $Gson$Types.resolve(type.getType(), raw, field.getGenericType());
List<String> fieldNames = getFieldNames(field);
BoundField previous = null;
for (int i = 0, size = fieldNames.size(); i < size; ++i) {
String name = fieldNames.get(i);
if (i != 0) serialize = false; // only serialize the default name
//
BoundField boundField = createBoundField(context, field, name,
TypeToken.get(fieldType), serialize, deserialize);
BoundField replaced = result.put(name, boundField);
if (previous == null) previous = replaced;
}
if (previous != null) {
throw new IllegalArgumentException(declaredType
+ " declares multiple JSON fields named " + previous.name);
}
}
type = TypeToken.get($Gson$Types.resolve(type.getType(), raw, raw.getGenericSuperclass()));
raw = type.getRawType();
}
return result;
}
- 其中调用了excludeField来判断字段是否参与反序列化或者序列化过程,实现如下
public boolean excludeField(Field f, boolean serialize) {
return excludeField(f, serialize, excluder);
}
static boolean excludeField(Field f, boolean serialize, Excluder excluder) {
return !excluder.excludeClass(f.getType(), serialize) && !excluder.excludeField(f, serialize);
}
//excludeClassChecks(clazz)检查class类型是否符合序列化或者反序列化要求,里面用到的Since和Until注解
//excludeClassInStrategy(clazz, serialize)通过加入自己的策略来控制字段是否要参与解析
//excluder.excludeField(f, serialize)过滤字段
public boolean excludeClass(Class<?> clazz, boolean serialize) {
return excludeClassChecks(clazz) ||
excludeClassInStrategy(clazz, serialize);
}
- 回到getBoundFields中,其调用了createBoundField来创建BoundField
createBoundField
private ReflectiveTypeAdapterFactory.BoundField createBoundField(
final Gson context, final Field field, final String name,
final TypeToken<?> fieldType, boolean serialize, boolean deserialize) {
//是否是基本数据类型
final boolean isPrimitive = Primitives.isPrimitive(fieldType.getRawType());
// special casing primitives here saves ~5% on Android...
//@JsonAdapter注解,如果实体类某属性使用了@JsonAdapter,那么该属性的序列化和反序列化将由指定的适配器接管。
//如果没有这会从Gson初始化中查找对于的解析适配器
JsonAdapter annotation = field.getAnnotation(JsonAdapter.class);
TypeAdapter<?> mapped = null;
if (annotation != null) {
mapped = jsonAdapterFactory.getTypeAdapter(
constructorConstructor, context, fieldType, annotation);
}
final boolean jsonAdapterPresent = mapped != null;
if (mapped == null) mapped = context.getAdapter(fieldType);
final TypeAdapter<?> typeAdapter = mapped;
return new ReflectiveTypeAdapterFactory.BoundField(name, serialize, deserialize) {
@SuppressWarnings({"unchecked", "rawtypes"}) // the type adapter and field type always agree
@Override void write(JsonWriter writer, Object value)
throws IOException, IllegalAccessException {
Object fieldValue = field.get(value);
TypeAdapter t = jsonAdapterPresent ? typeAdapter
: new TypeAdapterRuntimeTypeWrapper(context, typeAdapter, fieldType.getType());
t.write(writer, fieldValue);
}
@Override void read(JsonReader reader, Object value)
throws IOException, IllegalAccessException {
//typeAdapter.read
Object fieldValue = typeAdapter.read(reader);
if (fieldValue != null || !isPrimitive) {
field.set(value, fieldValue);
}
}
@Override public boolean writeField(Object value) throws IOException, IllegalAccessException {
if (!serialized) return false;
Object fieldValue = field.get(value);
return fieldValue != value; // avoid recursion for example for Throwable.cause
}
};
}