Kotlinx.serialization VS Gson

JSON is an open-standard file format or data interchange format that uses human-readable text to transmit data objects consisting of attribute-value pairs and array data types.

Java中常见的JSON解析库有MoshiJacksonGson等,因为Java和Kotlin互相兼容,所以这些库也可以用在Kotlin,虽然可能会有一些小坑。

我们基于Kotlin的data class定义一个User的Bean,agerole字段分被设置默认值以是之类型非空

data class User(
    val name: String,
    val email: String,
    val age: Int = 13,
    val role: Role = Role.Viewer
)

enum class Role { Viewer, Editor, Owner }

接下来,我们将下列JSON对象解析成User

{
    "name" : "John Doe",
    "email" : "john.doe@email.com"
}

先使用Gson写一个TestCase:

class JsonUnitTest {

    private val jsonString = """
            {
                "name" : "John Doe",
                "email" : "john.doe@email.com"
            }
        """.trimIndent()

    @Test
    fun gsonTest() {
        val user = Gson().fromJson(jsonString, User::class.java)

        assertEquals("John Doe",user.name)
        assertEquals(null, user.role)
        assertEquals(0, user.age)
//      User(name=John Doe, email=john.doe@email.com, age=0, role=null)
    }

}

上面的Test运行成功了。Gson在反序列化过程中,将基本型age设置了默认值0,将引用型role设置了null,这破坏了kotlin的非空类型编译期检查的限制,我们在调用user.role时可能出现crash。所以在Kotlin中进行反序列化时,我们希望能够遵循Kotlin的规范,识别这种非空类型。

Kotlinx.serialization

Kotlinx.serialization是Jetbrains针对Kotlin的推出序列化库。通过为KClass添加@Serializable注解,配合其配套的Kotlin Compiler Plugin,可以在编译期为在伴生对象中生成serializer()方法,serializer()方法返回一个KSerializer类型的序列化器。
KSerializer可以进行多种类型数据的序列化反序列化,例如 JSON、CBOR以及Protobuf

Kotlinx.serialization 还支持Kotlin MPP的跨平台使用,可以在JVM之外工作,例如用在Kotlin/Native或JavaScript中。

Kotlinx.serialization需要 Kotlin 1.3.30以上才可使用,如上所述,除了依赖runtime库以外, 还需要以来给一个Compiler Plugin用来进行字节码插桩。字节码插桩的一个直接好处就是可以实现零反射,性能更好。

我们基于Kotlinx.serialization测试一下上面的TestCase:

@Serializable
data class User(
    val name: String,
    val email: String,
    val age: Int = 13,
    val role: Role = Role.Viewer
)

enum class Role { Viewer, Editor, Owner }

class JsonUnitTest {

    private val jsonString = """
            {
                "name" : "John Doe",
                "email" : "john.doe@email.com"
            }
        """.trimIndent()

    @Test
    fun gsonTest() {
        val user = Gson().fromJson(jsonString, User::class.java)

        assertEquals("John Doe", user.name)
        assertEquals(null, user.role)
        assertEquals(0, user.age)
//      User(name=John Doe, email=john.doe@email.com, age=0, role=null)
    }

    @Test
    fun jsonTest() {
        val user = Json.parse(User.serializer(), jsonString)

        assertEquals("John Doe", user.name)
        assertEquals(Role.Viewer, user.role)
        assertEquals(13, user.age)
//      User(name=John Doe, email=john.doe@email.com, age=13, role=Viewer)
    }
}

测试通过可以看见Kotlinx.serialization反序列化结果中的缺省值是data class中定义的值,更符合预期。


Kotlinx.serialization + Retrofit

我们都经常使用Retrofit+Gson的组合进行HTTP请求以及对请求结果进行反序列化。 如今我们也可以为Retrofit 添加 新的ConverterFactory,以适配Kotlinx.serialization的使用。

我肯可以定义自己的ConverterFactory,也可以使用第三方现成的,例如J神已将帮我们写好的一个https://github.com/JakeWharton/retrofit2-kotlinx-serialization-converter

val contentType = "application/json".toMediaType()

val retrofit = Retrofit.Builder()
 .baseUrl("https://www.example.com")
 .addConverterFactory(
 	Json(JsonConfiguration(strictMode = false))
 	.asConverterFactory(contentType))
 .build()

可以通过JsonConfiguation进行配置,例如打开/关闭编码默认值,启用/禁用strictMode等。默认情况下strictMode处于启用状态,此时会检查JSON中是否存在unknown的key,并且不运行String像num类型的转换等。一个推荐做法是在debug模式下开启严格模式,在release包中关闭,可以提高线上的容错性。


最后

本文只是介绍了Kotlinx.serialization的基本用法,想了解更多内容可以参考官网以及 KotlinConf 2019: Design of Kotlin Serialization by Leonid Startsev

kotlinx.serialization是一个用于在Kotlin中进行对象序列化和反序列化的库。通过使用kotlinx.serialization库,我们可以将Kotlin对象转换为JSON格式的字符串,并将JSON格式的字符串转换回Kotlin对象。库的默认行为是在反序列化时填充默认值属性,以节省空间和带宽。在大多数情况下,这样做可以减少数据量,并简化代码。例如,可以在序列化和反序列化Project类时,自动填充language属性的默认值为"Kotlin",并且不会将该属性写入JSON字符串中。 此外,kotlinx.serialization库还支持可空属性的默认值为null。在序列化和反序列化Project类时,如果renamedTo属性的值为null,该属性将不会被写入JSON字符串中。 另外,kotlinx.serialization库还支持在可序列化类的属性中引用其他类。被引用的类也必须标记为@Serializable。例如,在Project类中引用了User类,可以将User对象作为Project对象的属性进行序列化和反序列化。 库还提供了对重复引用的支持,不会对重复引用进行压缩。例如,在Project类中同时引用了owner和maintainer属性,它们都指向同一个User对象,当序列化时,会在JSON字符串中分别表示这两个引用。 总之,kotlinx.serialization是一个功能强大的库,可以方便地进行对象的序列化和反序列化,并且支持默认值属性、可空属性、引用其他类以及重复引用等特性。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *2* *3* [千呼万唤始出来,Kotlin官方序列化库终相见(一)](https://blog.csdn.net/weixin_55362248/article/details/121906615)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 100%"] [ .reference_list ]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

fundroid

你的鼓励将是我创作的最大动力

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

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

打赏作者

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

抵扣说明:

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

余额充值