kotlin中Gson解析Json时对于泛型的应用

Gosn解析Json

我们都知道,在使用Gson解析json时,可以通过如下代码将json转为实体类

val user = Gson().fromJson(json, UserBean::class.java)

实体类的定义

而在开发过程中,我们也可能遇到这样的Json数据

//一个登陆接口返回的数据
{
    "data": {
        "admin": false,
        "chapterTops": [],
        "coinCount": 10,
        "collectIds": [],
        "email": "",
        "icon": "",
        "id": 136927,
        "nickname": "17398900708",
        "password": "",
        "publicName": "17398900708",
        "token": "",
        "type": 0,
        "username": "17398900708"
    },
    "errorCode": 0,
    "errorMsg": ""
}
//一个登陆失败的Json
{
    "data": null,
    "errorCode": -1,
    "errorMsg": "账号密码不匹配!"
}

和这样的Json数据

//一个获取首页banner的Json
{
    "data": [
        {
            "desc": "我们支持订阅啦~",
            "id": 30,
            "imagePath": "https://www.wanandroid.com/blogimgs/42da12d8-de56-4439-b40c-eab66c227a4b.png",
            "isVisible": 1,
            "order": 2,
            "title": "我们支持订阅啦~",
            "type": 0,
            "url": "https://www.wanandroid.com/blog/show/3352"
        },
        {
            "desc": "",
            "id": 6,
            "imagePath": "https://www.wanandroid.com/blogimgs/62c1bd68-b5f3-4a3c-a649-7ca8c7dfabe6.png",
            "isVisible": 1,
            "order": 1,
            "title": "我们新增了一个常用导航Tab~",
            "type": 1,
            "url": "https://www.wanandroid.com/navi"
        },
        {
            "desc": "一起来做个App吧",
            "id": 10,
            "imagePath": "https://www.wanandroid.com/blogimgs/50c115c2-cf6c-4802-aa7b-a4334de444cd.png",
            "isVisible": 1,
            "order": 1,
            "title": "一起来做个App吧",
            "type": 1,
            "url": "https://www.wanandroid.com/blog/show/2"
        }
    ],
    "errorCode": 0,
    "errorMsg": ""
}

通过对比我们可以发现,这几个Json具有共性的特点——它们都由data,errorCode,errorMsg这三部分组成,那么他们的实体该怎么书写呢?

像这样的实体,我们可能大概率是,像这样构建两个BaseBean,一个UserBean和一个BannerBean:

//用户基类
data class UserBaseBean (
    @SerializedName("data") val data : UserBean,
    @SerializedName("errorCode") val errorCode : Int,
    @SerializedName("errorMsg") val errorMsg : String
)
//bannar基类
data class BannerBaseBean (
    @SerializedName("data") val data : BannerBean,
    @SerializedName("errorCode") val errorCode : Int,
    @SerializedName("errorMsg") val errorMsg : String
)
//用户类
data class UserBean(...)
//banner类
data class BannerBean(...)

其他写法

那么有没有其他简单的写法呢,我们可能自然而然的会想到泛型,有没有可能存在这样一种写法呢:

data class BaseBean<T>(
    @SerializedName("data") val data: T,
    @SerializedName("errorCode") val errorCode: Int,
    @SerializedName("errorMsg") val errorMsg: String
)

很遗憾,Gson并不支持你做这么高端的操作:

//这种写法会提示类的左边只能是类
val user = Gosn().fromJson(json,BaseBean<UserBean>::class.java)

只要求获取data数据

虽然我们不能采用上面的写法来偷懒 提升开发效率,但在只需要data的数据的情况下,还是有一些提升的手段的:

1.使用JSONObject和Gson配合使用:

//response是请求接口返回的响应
val result = response.body?.string()
val jsonObject = result?.let { JSONObject(it) }
//通过jsonObject,我们可以轻松拿到data的json数据,然后使用gson将其解析
val user = Gson().fromJson(jsonObject.getString("data"),UserBean::class.java)

2.利用kotlin,对gson进行扩展:

我们可以参考如下文章进行操作,大佬写的十分详细

Java/Kotlin: Gson() 泛型转换,解决泛型参数的类型擦除

3.对第二种的方法进行修改:

在看完上述方法后,我也结合1中的方法,对2进行了小幅度的修改,并把它封装放到了一个类中,如下:

class JsonToBean {
    inline fun <reified T> Gson.fromJson2(json: String, type: Type): T? {
        val jsonObject = JSONObject(json)
        val data = jsonObject.getString("data")
        return if (data.isEmpty()) {
            null
        } else {
            fromJson(data, type)
        }
    }

    inline fun <reified T> toBean(json: String): T? {
        val typeT = object : TypeToken<T>() {}.type
        return Gson().fromJson2<T>(json, typeT)
    }
}

使用的方法如下:

//result为上述response.body?.string()得到的值
val user = JsonToBean().toBean<UserBean>(result)

以上就是我对最近在开发中对json解析的一些新的感悟,当然由于我目前还在学习kotlin,对于kotlin理解不够深刻,欢迎有更好的办法的大佬对我不吝赐教

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
Kotlin 使用 Gson.registerTypeAdapterFactory() 方法,需要先定义一个 TypeAdapterFactory 类型的对象,然后将其作为参数传递到 registerTypeAdapterFactory() 方法。 例如,假设我们有一个自定义的类型 MyType,我们想要在 Gson 序列化和反序列化这个类型。我们可以定义一个 MyTypeAdapterFactory 类来实现 TypeAdapterFactory 接口,并在该类实现对 MyType 的序列化和反序列化逻辑。代码如下: ```kotlin class MyTypeAdapterFactory : TypeAdapterFactory { override fun <T : Any?> create(gson: Gson?, type: TypeToken<T>?): TypeAdapter<T>? { if (type?.rawType == MyType::class.java) { val delegate = gson?.getDelegateAdapter(this, type) return MyTypeAdapter(delegate as TypeAdapter<MyType>) } return null } } class MyTypeAdapter(private val delegate: TypeAdapter<MyType>) : TypeAdapter<MyType>() { override fun write(out: JsonWriter?, value: MyType?) { // 实现 MyType 的序列化逻辑 delegate.write(out, value) } override fun read(`in`: JsonReader?): MyType { // 实现 MyType 的反序列化逻辑 return delegate.read(`in`) } } ``` 然后,在使用 Gson 进行序列化和反序列化的候,我们可以将 MyTypeAdapterFactory 对象作为参数传递到 registerTypeAdapterFactory() 方法,如下所示: ```kotlin val gson = GsonBuilder() .registerTypeAdapterFactory(MyTypeAdapterFactory()) .create() val myType = MyType() val json = gson.toJson(myType) val myType2 = gson.fromJson<MyType>(json, MyType::class.java) ``` 这样,我们就可以在 Kotlin 使用 Gson.registerTypeAdapterFactory() 方法来注册自定义的 TypeAdapterFactory 实现了。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值