Gson直接将json转list示例 (TypeToken)以及通过内联函数结合reified简化代码

为了演示,我们新建一个简单的数据类Person
数据类Person

data class Person(var name: String = "", var age: Int = 0)

json数据反序列化为普通对象

使用Gson将Json数据直接转成普通实体类很简单,如下

 Gson().fromJson<Person>(personsJson,Person::class.java)

json数据反序列化为集合

有的时候,我们可能需要直接将一段json数据转成一个List
例如下面的json数据。

[{"age":1,"name":"yzq"},{"age":2,"name":"yzq"},{"age":3,"name":"yzq"},{"age":4,"name":"yzq"},{"age":5,"name":"yzq"},{"age":6,"name":"yzq"},{"age":7,"name":"yzq"},{"age":8,"name":"yzq"},{"age":9,"name":"yzq"},{"age":10,"name":"yzq"}]

我们先来看看Gson的源码说明,注释已经告诉我们了需要用到TypeToken

在这里插入图片描述
将json直接转为list,通过TypeToken来实现,代码如下

	private lateinit var newPersons: ArrayList<Person>
	val listType = object : TypeToken<ArrayList<Person>>() {}.type
	newPersons = Gson().fromJson(personsJson, listType)

我们来打印下反序列化后的newPersons

[Person(name=yzq, age=1), Person(name=yzq, age=2), Person(name=yzq, age=3), Person(name=yzq, age=4), Person(name=yzq, age=5), Person(name=yzq, age=6), Person(name=yzq, age=7), Person(name=yzq, age=8), Person(name=yzq, age=9), Person(name=yzq, age=10)]

这样我们就完成了直接将json数据转为集合。


封装以及运行期泛型擦除的坑

在日常开发中,我们一般会封装一个通用的GsonUtil在简化代码。

对于直接将json转list,我们可能会这样写:

package com.yzq.kotlin.demo

import com.google.gson.Gson
import com.google.gson.GsonBuilder
import com.google.gson.reflect.TypeToken


/**
 * @description: Gson 工具类
 * @author : yuzhiqiang (zhiqiang.yu.xeon@gmail.com)
 */
object GsonUtil {

    val gson: Gson = GsonBuilder()
        .serializeNulls()
        .setLenient()
        .create()

    fun <T> fromJson(json: String): T {
        return gson.fromJson(json, object : TypeToken<T>() {}.type)
    }
    fun toJson(src: Any): String {
        return gson.toJson(src)
    }


}

然后这样用:

    val jsonArr =
        "[{\"age\":1,\"name\":\"yzq\"},{\"age\":2,\"name\":\"yzq\"},{\"age\":3,\"name\":\"yzq\"},{\"age\":4,\"name\":\"yzq\"},{\"age\":5,\"name\":\"yzq\"},{\"age\":6,\"name\":\"yzq\"},{\"age\":7,\"name\":\"yzq\"},{\"age\":8,\"name\":\"yzq\"},{\"age\":9,\"name\":\"yzq\"},{\"age\":10,\"name\":\"yzq\"}]"
    val personList = GsonUtil.fromJson<ArrayList<Person>>(jsonArr)

    println("personList = ${personList}")


然后我们运行看一下结果:

在这里插入图片描述
可以看到,正常打印了,好像没有什么问题。那我们再加一点代码,如下:

    val jsonArr =
        "[{\"age\":1,\"name\":\"yzq\"},{\"age\":2,\"name\":\"yzq\"},{\"age\":3,\"name\":\"yzq\"},{\"age\":4,\"name\":\"yzq\"},{\"age\":5,\"name\":\"yzq\"},{\"age\":6,\"name\":\"yzq\"},{\"age\":7,\"name\":\"yzq\"},{\"age\":8,\"name\":\"yzq\"},{\"age\":9,\"name\":\"yzq\"},{\"age\":10,\"name\":\"yzq\"}]"
    val personList = GsonUtil.fromJson<ArrayList<Person>>(jsonArr)

    println("personList = ${personList}")

    personList.forEach {

        println(it.name)
    }

我们只是在将json转成list后对list做遍历打印值,运行看看代码:

在这里插入图片描述

结果发现报错了,报错信息如下

com.google.gson.internal.LinkedTreeMap cannot be cast to com.yzq.kotlin.demo.Person

原因是泛型类型在运行时会被擦除,导致了该问题。

那我们又不想每次将json转list都去写 object : TypeToken<ArrayList>() {}.type 这样的代码怎么办。

val fromJson = Gson().fromJson<Any>(jsonArr, object : TypeToken<ArrayList<Person>>() {}.type)

我们可以使用kotlin内联函数中的reified 来解决该问题。

Kotlin 内联函数官方文档

reified:具体化的类型参数,可以在运行时也访问到泛型的具体类型。

那我们就将上面那个toJosn方法改成这样:

   inline fun <reified T> fromJson(json: String): T {
        return gson.fromJson(json, object : TypeToken<T>() {}.type)
    }

然后再来跑一遍代码:

在这里插入图片描述

可以看到,没有报错,而且打印的personList中能够明确的看到是Person类型,上面那个并没有Person类型的显示,那这样一来,我们fromJson代码写起来就简洁许多了

下面是我日常开发用的代码,很简单,需要可以参考。

package com.yzq.kotlin.demo

import com.google.gson.Gson
import com.google.gson.GsonBuilder
import com.google.gson.reflect.TypeToken


/**
 * @description: Gson 工具类
 * @author : yuzhiqiang (zhiqiang.yu.xeon@gmail.com)
 */
object GsonUtil {

    val gson: Gson = GsonBuilder()
        .serializeNulls()
        .setLenient()
        .create()

    private val prettyGson: Gson = GsonBuilder()
        .serializeNulls()
        .setPrettyPrinting()
        .setLenient()
        .create()


    fun <T> fromJson(json: String, classOfT: Class<T>): T {
        return gson.fromJson(json, classOfT)
    }

    inline fun <reified T> fromJson(json: String): T {
        return gson.fromJson(json, object : TypeToken<T>() {}.type)
    }

    fun toJson(src: Any): String {
        return gson.toJson(src)
    }

    fun toPrettyJson(src: Any): String {
        return prettyGson.toJson(src)
    }

    fun toJson(src: Any, typeOfSrc: Type): String {
        return gson.toJson(src, typeOfSrc)
    }

}

日常开发中,使用Gson时都会有一些小技巧,让我们使用Gson更加简洁。感兴趣的可以看下面这片博客

Gson使用的一些小技巧

本篇博客就是这些,希望对你有帮助。


如果你觉得本文对你有帮助,麻烦动动手指顶一下,算是对本文的一个认可,如果文中有什么错误的地方,还望指正,转载请注明转自喻志强的博客 ,谢谢!

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

喻志强(Xeon)

码字不易,鼓励随意。

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值