简单对比下 Moshi 和 Kotlinx.serialization

上一篇我们对比介绍了 Gson 和 Kotlinx.serialization,很多小伙伴在后台留言说,moshi 呢?

Moshi 怎么解决 Kotlin 数据类的问题?

首先必须说的是,Moshi 这个框架也算是 Jake 大神的良心之作了,无论从功能上,还是从使用的角度,这个框架值得推荐。

我们上一篇文章提到 Gson 不认识 Kotlin,所以对 Kotlin 的数据类几乎没有支持,这包括构造器的默认值、初始化逻辑的调用等等,而 Moshi 则类似于 Kotlinx.serialization,为我们解决了这一问题。

其实如果我们不看 Moshi 和 KS 的实现,我们单纯猜测他们要如何解决这一难题的话,无非就是使用 Kotlin 反射或使用注解处理器等方法来获取到 Kotlin 类的主构造器,以及它的参数类型和参数名(注意Kotlin反射是可以获取到参数名的哦~当然如果你用了混淆,那么这里会有问题),所以对于下面的情况:

 
 
  1. data class Data(val id: Int, val name: String, val age: Int)

即便我们的 Json 中 K-V 的顺序是乱序的:

 
 
  1. {"name": "bennyhuo", "id": 1000, "age": 20}

使用 Kotlin 反射,一样可以正确的将 Json 的数据结构与 Data 的主构造器的参数一一正确对应。使用注解处理器那就更不用说了。Moshi 的解决方法就是这样,它为我们提供了两种选择,你可以选择使用 Kotlin 反射,那样的话你需要忍受 Kotlin 反射 2.5M 的 jar 包以及相对较慢的运行时开销;你也可以选择注解处理器的方式,

 
 
  1. @JsonClass(generateAdapter = true)

  2. data class Data(val id: Int, val name: String, val age: Int)

Moshi 可以为前面的 Data 生成一个 Adapter

 
 
  1. class DataJsonAdapter(moshi: Moshi) : JsonAdapter<Data>() {

  2.    private val options: JsonReader.Options = JsonReader.Options.of("id", "name", "age")

  3.    ...

  4.    override fun fromJson(reader: JsonReader): Data {

  5.        var id: Int? = null

  6.        var name: String? = null

  7.        var age: Int? = null

  8.        reader.beginObject()

  9.        while (reader.hasNext()) {

  10.            when (reader.selectName(options)) {

  11.                0 -> id = intAdapter.fromJson(reader) ?: throw JsonDataException("Non-null value 'id' was null at ${reader.path}")

  12.                1 -> name = stringAdapter.fromJson(reader) ?: throw JsonDataException("Non-null value 'name' was null at ${reader.path}")

  13.                2 -> age = intAdapter.fromJson(reader) ?: throw JsonDataException("Non-null value 'age' was null at ${reader.path}")

  14.                -1 -> {

  15.                    // Unknown name, skip it.

  16.                    reader.skipName()

  17.                    reader.skipValue()

  18.                }

  19.            }

  20.        }

  21.        reader.endObject()

  22.        var result = Data(

  23.                id = id ?: throw JsonDataException("Required property 'id' missing at ${reader.path}"),

  24.                name = name ?: throw JsonDataException("Required property 'name' missing at ${reader.path}"),

  25.                age = age ?: throw JsonDataException("Required property 'age' missing at ${reader.path}"))

  26.        return result

  27.    }

  28.    override fun toJson(writer: JsonWriter, value: Data?) {

  29.        ...

  30.    }

  31. }

大家可以自己试一试,考虑篇幅我只保留了 fromJson 的实现,大家可以参考。

Kotlin.serialization 怎么解决 Kotlin 数据类的问题?

那么同样的问题我们再问一问 KS。KS 的思路实际上与 Moshi 的注解处理器类似,只不过它因为更靠近 Kotlin 官方,是嫡系,因此它可以把一些工作放到编译器里面做。

 
 
  1. @Serializable

  2. data class Data(val id: Int, val name: String, val age: Int)

同样用 Data 这个类为例,我们按照 KS 的要求配置好之后,编译,我们可以在 Data 的字节码当中找到一些额外的东西:

 
 
  1. public static final class $serializer implements KSerializer {

  2.  public static final Data.$serializer INSTANCE;

  3.  private static final KSerialClassDesc $$serialDesc;

  4.  public Data update(@NotNull KInput input, @NotNull Data old) { ... }

  5.  public Object update(KInput var1, Object var2) { ... }

  6.  public KSerialClassDesc getSerialClassDesc() { ... }

  7.  public void save(@NotNull KOutput output, @NotNull Data obj) { ... }

  8.  public Data load(@NotNull KInput input) { ... }

  9.  ...

  10. }

$serializer 就是 KS 为 Data 生成的默认的序列化类,这样的做法其实与注解处理器有异曲同工之妙,只不过直接生成字节码的方式可以修改原有的类,因此作为 Data 的内部类, $serializer 可以访问 Data 的私有成员(如果有的话)。

Moshi 和 Kotlin.serialization 的对比

这二者从能力上,对 Kotlin 的支持其实差异不大,下面我简单它们适合的场景。

  • KS 的优势是支持 Kotlin 的 Multiplatform,对于需要多平台移植的 Kotlin 代码,使用 KS 显然更合适。

  • Moshi 的优势是兼容 Java ,毕竟 Kotlin 的代码 90% 仍然跑在 Jvm 甚至 Android 上,所以如果你的 Kotlin 代码与 Java 代码混合运行在 Jvm 上面,那么考虑使用 Moshi。


对啦,我的 Kotlin 新课 “基于 GitHub App 业务深度讲解 Kotlin1.2高级特性与框架设计” 上线之后,大家普遍反映有难度,有深度,如果哪位朋友想要吊打 Kotlin,不妨来看看哦!

https://coding.imooc.com/class/232.html

640?wx_fmt=jpeg

转载请注明出处:微信公众号 Kotlin

640?wx_fmt=jpeg

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值