Kotlin与Gson与Moshi

Kotlin与Gson与Moshi

Safe Parsing Kotlin Data-classes with Gson

Gson在Kotlin中的问题

Kotlin的Data Classes非空类型很好用,Gson解析库也很好用,但是当他们两个结合起来时就非常的糟糕……

假设服务器某个api会给我们返回这样的json,它只有两个参数,但是却可能出现非常多种情况:

  1. null
  2. {}
  3. {"strValue":"default"}
  4. {"intValue":2}
  5. {"intValue"=2,"strValue"=null}
  6. {"intValue"=2,"strValue"="default"}

为了App的稳定性,我们必须将以上情况都考虑到,不能因为服务器的问题让我们app莫名奇妙的崩溃,即使你们后台同事跟你说不可能出现这样的json也不行,任何时候都不要相信json数据的完整性和正确性

如果我们将data class定义成这样,然后使用Gson解析:

data class SomeData(
    val intValue: Int,
    val strValue: String
)

上面全部json都能解析成功,这就导致了我们声明的非空类型指向了null,最终肯定触发空指针异常

如果给data class的属性都赋予默认值:

data class SomeData(
    val intValue: Int = 0,
    val strValue: String = "default value"
)

上面全部json都能解析成功,但是第五种情况会让strValue覆盖默认值变为null,最终还是导致非空类型指向了null。

所以使用Gson解析时,我们能信任的data class只有下面这种,将所有字段设为可空类型

data class SomeData(
    val intValue: Int?,
    val strValue: String?
)

希望是什么样的

data class SomeData(
    val intValue: Int,
    val strValue: String
)

我希望上面的intValue和strValue在没有值{}或为空null时就给我抛出解析异常,除非我将他们定义为nullable

而Moshi正好能满足这样的要求

Moshi

扩展阅读: 官方文档新一代Json解析库Moshi使用及原理解析

空安全和泛型支持的测试:https://github.com/AItsuki/AndroidSamples/blob/master/moshi/src/test/java/com/aitsuki/sample/moshi/MoshiWithKotlinNullSafeTest.kt

  • kotlin支持(空安全)
  • square出品,可配合Retrofit使用
  • 支持反射or注解器两种方式,并且可以混用(android上推荐只使用注解器方式)

导入:

implementation "com.squareup.moshi:moshi:$moshiVersion"
kapt "com.squareup.moshi:moshi-kotlin-codegen:$moshiVersion"
kaptTest "com.squareup.moshi:moshi-kotlin-codegen:$moshiVersion" // 测试
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 实现了。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值