tokuhirom's Blog

kotlinx.serialization のこと

kotlinx.serialization は、kotlin 用のシリアライゼーションライブラリである。 gradle のプラグインが提供されていて、@Serializable アノテーションがついているクラスに対するシリアライザを生成してくれる。 プラグインのソースコードは https://github.com/JetBrains/kotlin/tree/master/plugins/kotlinx-serialization にある。なにかコード生成ライブラリ使ってるのかと思ったら kotlin そのものの機能を使ってそう。

kotlinx.serialization のドキュメントは以下の場所にある。Polymorphism のような機能があって Jackson に出来ることは一通りできそう。 https://github.com/Kotlin/kotlinx.serialization/blob/4bf4113c2c6936e841caf2a8670382e701e7fcc2/docs/serialization-guide.md

たとえば以下のように使うのだが、、

package org.example

import kotlinx.serialization.Serializable
import kotlinx.serialization.encodeToString
import kotlinx.serialization.json.Json

@Serializable
data class Greeting(val greeting: String)

fun main() {
    println("Hello World!")
    println(Json.encodeToString(Greeting("Hello, Kotlin/JS!")))
}

生成されるコードは以下のようになっている。Greeting$serializer.serialize が生成されてるので、実行時には高速に処理ができそうだ。 (kotlin のデコンパイルを IDEA がサポートしてほしいなぁと思いつつ幾星霜)

// IntelliJ API Decompiler stub source generated from a class file
// Implementation of methods is not available

package org.example

@kotlinx.serialization.Serializable public final data class Greeting public constructor(greeting: kotlin.String) {
    public companion object {
        public final fun serializer(): kotlinx.serialization.KSerializer<org.example.Greeting> { /* compiled code */ }
    }

    internal constructor(seen0: kotlin.Int, greeting: kotlin.String?, serializationConstructorMarker: kotlinx.serialization.internal.SerializationConstructorMarker?) { /* compiled code */ }

    public final val greeting: kotlin.String /* compiled code */

    public final operator fun component1(): kotlin.String { /* compiled code */ }

    public open operator fun equals(other: kotlin.Any?): kotlin.Boolean { /* compiled code */ }

    public open fun hashCode(): kotlin.Int { /* compiled code */ }

    public open fun toString(): kotlin.String { /* compiled code */ }

    @kotlin.jvm.JvmStatic internal final fun `write$Self`(self: org.example.Greeting, output: kotlinx.serialization.encoding.CompositeEncoder, serialDesc: kotlinx.serialization.descriptors.SerialDescriptor): kotlin.Unit { /* compiled code */ }

    @kotlin.Deprecated public object `$serializer` : kotlinx.serialization.internal.GeneratedSerializer<org.example.Greeting> {
        public final val descriptor: kotlinx.serialization.descriptors.SerialDescriptor /* compiled code */

        public final fun childSerializers(): kotlin.Array<kotlinx.serialization.KSerializer<*>> { /* compiled code */ }

        public final fun deserialize(decoder: kotlinx.serialization.encoding.Decoder): org.example.Greeting { /* compiled code */ }

        public final fun serialize(encoder: kotlinx.serialization.encoding.Encoder, value: org.example.Greeting): kotlin.Unit { /* compiled code */ }
    }
}

さて、実際速度的にはどうなのかな? というのが気になりますよね。 kotlinx.serialization のレポジトリ、ちゃんとベンチマークコードが入っているのに、結果をのせてないところが奥ゆかしいですね。 https://github.com/Kotlin/kotlinx.serialization/blob/4bf4113c2c6936e841caf2a8670382e701e7fcc2/benchmark/src/jmh/kotlin/kotlinx/benchmarks/json/JacksonComparisonBenchmark.kt

./gradlew jmh

とかすれば、結果が得られるので、手元で動かして結果を見てみると良さそう。

Benchmark                                               Mode  Cnt      Score      Error   Units
JacksonComparisonBenchmark.jacksonFromString           thrpt   10    731.704 ±   17.971  ops/ms
JacksonComparisonBenchmark.jacksonSmallToString        thrpt   10   9779.674 ± 3045.866  ops/ms
JacksonComparisonBenchmark.jacksonToString             thrpt   10   1811.471 ±   55.360  ops/ms
JacksonComparisonBenchmark.jacksonToStringWithEscapes  thrpt   10   1508.877 ±  122.538  ops/ms
JacksonComparisonBenchmark.kotlinFromStream            thrpt   10   1080.475 ±   82.937  ops/ms
JacksonComparisonBenchmark.kotlinFromString            thrpt   10   1375.436 ±   89.197  ops/ms
JacksonComparisonBenchmark.kotlinSmallToOkio           thrpt   10   8141.993 ±  111.842  ops/ms
JacksonComparisonBenchmark.kotlinSmallToStream         thrpt   10  10325.260 ± 2784.316  ops/ms
JacksonComparisonBenchmark.kotlinSmallToString         thrpt   10  10832.368 ±  306.662  ops/ms
JacksonComparisonBenchmark.kotlinToOkio                thrpt   10    898.711 ±   26.997  ops/ms
JacksonComparisonBenchmark.kotlinToStream              thrpt   10   1011.233 ±   62.126  ops/ms
JacksonComparisonBenchmark.kotlinToString              thrpt   10   1912.123 ±  192.133  ops/ms
JacksonComparisonBenchmark.kotlinToStringWithEscapes   thrpt   10   1336.079 ±  303.871  ops/ms

結果はこんな感じになる。 chatgpt で markdown に整形した結果が以下。そんなにすごい差があるわけでもない。