探索Android开源框架 - 8. Gson使用及源码解析
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 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 } }; }
作者:今阳
链接:https://juejin.cn/post/7037416949151694861
伪原创工具 SEO网站优化 https://www.237it.com/