val gson = GsonBuilder().create()
/**
* 通过kotlin语法特性创建Type类
*/
abstract class GsonParameterizedType<T> : ParameterizedType
inline fun <reified T> String.fromJson(customType: GsonParameterizedType<T>? = null): T {
if (T::class.java == String::class.java) {
return this as T
}
return gson.fromJson(this, customType ?: object : TypeToken<T>() {}.type)
}
inline fun <reified T> createGsonParameterizedType(
crossinline actualTypeArguments: () -> Array<Type>,
): GsonParameterizedType<T> {
return object : GsonParameterizedType<T>() {
override fun getActualTypeArguments(): Array<Type> {
return actualTypeArguments.invoke()
}
override fun getRawType(): Type {
return T::class.java
}
override fun getOwnerType() = null
}
}
inline fun <reified T> String.fromJsonList(): List<T> {
return fromJson(createGsonParameterizedType<List<T>> { //这里其实省略了List<T>。因此传给fromJson的实体类是List<XX>对象,
arrayOf(T::class.java)
})
}
inline fun <reified T> String.fromJsonList2(): List<T> {
val listType = object : TypeToken<List<T>>() {}.type
return gson.fromJson(this, listType)
}
//错误!
inline fun <reified T> String.fromJsonList3(): T { //JsonSyntaxException: java.lang.IllegalStateException: Expected BEGIN_ARRAY but was STRING at line 1 column 3 path $[0]
return fromJson(createGsonParameterizedType {
arrayOf(T::class.java)
})
}
//错误!
inline fun <reified T> String.fromJsonList4(): T { //JsonSyntaxException: java.lang.IllegalStateException: Expected BEGIN_ARRAY but was STRING at line 1 column 3 path $[0]
val listType = object : TypeToken<List<T>>() {}.type
return gson.fromJson(this, listType)
}
如上是一些基础函数。
- 一、获取List对象
有如下2种和直接调用fromJson()共计3种方式:
//1. 2. fromJsonList 或者 fromJsonList2
val list<List<XXXBean>> = xxxStr.fromJsonList() //fromJsonList2()
//3. 直接写调用
fromJson<List<XXXBean>>(createGsonParameterizedType {
arrayOf(XXXBean::class.java)
})
- 二、获取其他泛型类型
class CommonResponse<T, G> {
var status = 0
var data: T? = null
var data2:G? = null
}
class CommonResponse<T> {
var status = 0
var data: T? = null
}
class CommonResponse2 {
var status = 0
var data: Any? = null
}
class DataInfo {
var name: String? = null
}
fun testGsonData() {
val text = "{\"status\":102,\"data\":{\"name\":\"dog\"}, \"data2\":{\"name\":\"dog2\"}}"
// IllegalStateException: Expected a string but was BEGIN_OBJECT at line 1 column 22 path $.data
//val data:CommonResponse<String> = text.fromJson()
//正确:通过传入Type,明确指定了我们需要解析的泛型是什么。
val data:CommonResponse<DataInfo, DataInfo> //这里写的是2个相同泛型,可以不同;一般我们只有1个泛型。下面也只arrayOf1个。
= text.fromJson(
createGsonParameterizedType {
arrayOf(DataInfo::class.java, DataInfo::class.java) //根据你的泛型类型的数组
})
//正确
val data:CommonResponse<DataInfo>
= text.fromJson(
createGsonParameterizedType {
arrayOf(DataInfo::class.java) //根据你的泛型类型的数组
})
logd("data $data")
//LinkedTreeMap {name:dog} : 因为是Any即Object,gson默认都是处理成基础类型或者List,Map
val data2 = gson.fromJson<CommonResponse2>(text, CommonResponse2::class.java)
//错误:不符合预期,这里得到的与data2一样,是LinkedTreeMap {name:dog}。
// 虽然我们写了泛型,但是由于这里没有实际意义,编译后被擦除,最终与上述差不多
val data3 = gson.fromJson<CommonResponse<DataInfo, DataInfo>>(text, CommonResponse::class.java)
}
总结:
本质上,List类型和自定义泛型数据类型,都是一样的。在编译后被擦除。只是我们可能下意识习惯了,自定义类型,不是数组可能更能理解我们比如传入解析方式。
而List也一样。也是一个class类型,内部的T泛型类型,需要我们指定。
另外查看,gson官方文档,配置混淆规则如下,否则混淆编译后报错:
https://github.com/google/gson/issues/2069
https://github.com/google/gson/blob/master/examples/android-proguard-example/proguard.cfg
##---------------Begin: proguard configuration for Gson ----------
# Gson uses generic type information stored in a class file when working with fields. Proguard
# removes such information by default, so configure it to keep all of it.
-keepattributes Signature
# For using GSON @Expose annotation
-keepattributes *Annotation*
# Gson specific classes
-dontwarn sun.misc.**
#-keep class com.google.gson.stream.** { *; }
# Application classes that will be serialized/deserialized over Gson
-keep class com.google.gson.examples.android.model.** { <fields>; }
# Prevent proguard from stripping interface information from TypeAdapter, TypeAdapterFactory,
# JsonSerializer, JsonDeserializer instances (so they can be used in @JsonAdapter)
-keep class * extends com.google.gson.TypeAdapter
-keep class * implements com.google.gson.TypeAdapterFactory
-keep class * implements com.google.gson.JsonSerializer
-keep class * implements com.google.gson.JsonDeserializer
# Prevent R8 from leaving Data object members always null
-keepclassmembers,allowobfuscation class * {
@com.google.gson.annotations.SerializedName <fields>;
}
# Retain generic signatures of TypeToken and its subclasses with R8 version 3.0 and higher.
-keep,allowobfuscation,allowshrinking class com.google.gson.reflect.TypeToken
-keep,allowobfuscation,allowshrinking class * extends com.google.gson.reflect.TypeToken
##---------------End: proguard configuration for Gson ----------
# 如下两条自行考虑追加也进行了保护。一般也添加
-keep class org.json.* {*;}
-keep public class * implements java.lang.reflect.Type