IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 移动开发 -> 探索Android开源框架 - 8. Gson使用及源码解析 -> 正文阅读

[移动开发]探索Android开源框架 - 8. Gson使用及源码解析

  • Gson 是 我们经常用来在 Java 对象和 JSON 数据之间进行映射的 库,今天我们就来分别讲一讲其使用和源码分析

使用详解

1. 基本的解析与生成

  • Gson提供了fromJson() 和toJson() 两个直接用于解析和生成的方法,前者实现反序列化,后者实现了序列化
  1. 解析基本数据类型
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")
  1. 生成基本数据类型
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")
  1. 解析及生成自定义对象
//先定义一个数据模型类,这里需要注意的一点是在方法内部定义的类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中的值为准
  • 为字段提供备选属性名,当多种情况同时出时,以最后一个出现的值为准
  1. 为数据模型类添加注解
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,
)
  1. 解析与生成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 两个方法;
  1. 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())}")
  1. 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的流式反序列化
  1. 手动的方式: 使用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")
  1. 自动方式最终都是通过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的流式序列化
  1. 手动
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")
  1. 自动
// 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方法并最终调用这两个抽象方法。
  1. 自定义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
    }
}
  1. 为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型,如果有些情况下给你返了个空字符串怎么办
  1. 用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
        }
    }
}
  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
        }
    }

}
  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
      }
    };
}

参考

  移动开发 最新文章
Vue3装载axios和element-ui
android adb cmd
【xcode】Xcode常用快捷键与技巧
Android开发中的线程池使用
Java 和 Android 的 Base64
Android 测试文字编码格式
微信小程序支付
安卓权限记录
知乎之自动养号
【Android Jetpack】DataStore
上一篇文章      下一篇文章      查看所有文章
加:2021-12-04 13:33:24  更:2021-12-04 13:33:59 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/24 6:22:29-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码