6
6

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

Kotlin 1.3.70 + kotlinx.serialization 0.20.0 の変更点に対応する

Last updated at Posted at 2020-03-06

Kotlin 1.3.70 がリリースされました https://blog.jetbrains.com/kotlin/2020/03/kotlin-1-3-70-released/

kotlinx.serialization を 0.20.0 へアップデートする必要がありますが、いくつかコードの修正が必要になります。

SerialDescriptor の変更

kotlinx.serialization 0.14.0 までは、カスタムシリアライザを実装するときは以下のような形式でした。

// Klock を使っています
@Serializer(DateTimeTz::class)
class KlockDateTimeTzIso8601Serializer : KSerializer<DateTimeTz> {
    companion object {
        fun formatter(): DateFormat {
            return DateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSXXX")
        }
    }

    private val format: DateFormat = formatter()
    override val descriptor: SerialDescriptor = StringDescriptor.withName("DateTimeTz")

    override fun serialize(encoder: Encoder, obj: DateTimeTz) {
        encoder.encodeString(format.format(obj))
    }

    override fun deserialize(decoder: Decoder): DateTimeTz {
        return format.parse(decoder.decodeString())
    }
}

これは以下のビルドエラーとなります。

Using 'withName(String): SerialDescriptor' is an error. Deprecated in the favour of PrimitiveDescriptor factory function

StringDescriptor が非推奨になっているため、descriptor を PrimitiveDescriptor 形式へ書き換えます。

override val descriptor: SerialDescriptor = PrimitiveDescriptor("DateTimeTz", PrimitiveKind.STRING)

PrimitiveDescriptor は https://github.com/Kotlin/kotlinx.serialization/blob/146a0d08ed87a97cf5435a89fcafd3aa639c106e/runtime/commonMain/src/kotlinx/serialization/SerialDescriptorBuilder.kt#L60 に実装されています。

PrimitiveDescriptor はシリアライズに encoder.encodeString decoder.decodeString を使用している場合に PrimitiveKind.STRING を指定します。

encoder.encodeLong decoder.decodeLong を使っている場合は PrimitiveKind.LONG です。

https://github.com/Kotlin/kotlinx.serialization/blob/146a0d08ed87a97cf5435a89fcafd3aa639c106e/runtime/commonMain/src/kotlinx/serialization/SerialKinds.kt#L54 こちらにすべての Primitive 型が定義されています。

public object BOOLEAN : PrimitiveKind()
public object BYTE : PrimitiveKind()
public object CHAR : PrimitiveKind()
public object SHORT : PrimitiveKind()
public object INT : PrimitiveKind()
public object LONG : PrimitiveKind()
public object FLOAT : PrimitiveKind()
public object DOUBLE : PrimitiveKind()
public object STRING : PrimitiveKind()

シリアライズ時に複数のデータをエンコード・デコードする場合は PrimitiveDescriptor ではなく、 SerialDescriptor を使用し、保持するデータごとにキーを指定します。

SerialDescriptor https://github.com/Kotlin/kotlinx.serialization/blob/146a0d08ed87a97cf5435a89fcafd3aa639c106e/runtime/commonMain/src/kotlinx/serialization/SerialDescriptorBuilder.kt#L9

* // Descriptor for such class: |
* SerialDescriptor("my.package.Data") { |
*     // intField is deliberately ignored by serializer -- not present in the descriptor as well |
*     element<Long>("_longField") // longField is named as _longField |
*     element("stringField", listDescriptor<String>()) |
* }

builtins package への置き換え

bultins package へ移動した機能があります。

import kotlinx.serialization.list
MyClass.serializer().list
// -> Using 'list: KSerializer<List<T>>' is an error. Deprecated in the favour of the same extension from builtins package

import kotlinx.serialization.builtins.list
MyClass.serializer().list

import kotlinx.serialization.internal.StringSerializer
StringSerializer()
// -> Using 'StringSerializer' is an error. Deprecated in the favour of String.serializer() extension

import kotlinx.serialization.builtins.serializer
String.serializer()

Json.plain, Json.nonstrict ルールの置き換え

Json.plain, Json.nonstritc などの Json パーサー設定も非推奨となりました。
Json パーサールールが細分化されているため、 JsonConfiguration から設定しましょう。

Json.nonstrict 設定は https://github.com/Kotlin/kotlinx.serialization/blob/146a0d08ed87a97cf5435a89fcafd3aa639c106e/runtime/commonMain/src/kotlinx/serialization/json/Json.kt#L193 がもとの設定です。

         public val nonstrict = Json(
             JsonConfiguration(
                 isLenient = true,
                 ignoreUnknownKeys = true,
                 serializeSpecialFloatingPointValues = true,
                 useArrayPolymorphism = true
             )
         )

これを参考に、以下のように書き換えます。

import kotlinx.serialization.json.Json
Json.nonstrict
// -> 'nonstrict: Json' is deprecated. Top-level JSON instances are deprecated for removal in the favour of user-configured one. You can either use a Json top-level object, configure your own instance  via 'Json {}' builder-like constructor, 'Json(JsonConfiguration)' constructor or by tweaking stable configuration 'Json(JsonConfiguration.Stable.copy(prettyPrint = true))'

Json {
    isLenient = true
    ignoreUnknownKeys = true
    serializeSpecialFloatingPointValues = true
    useArrayPolymorphism = true
}

ただし、これでは kotlinx.serialization のバージョンアップ時にデフォルトの Json 設定が変更されてしまうと、その影響を受けてしまいます。
バージョンアップの影響を受けないようにするには JsonConfiguration.Stable を使います。

Json(JsonConfiguration.Stable.copy(
    ignoreUnknownKeys = true,
    isLenient = true,
    serializeSpecialFloatingPointValues = true,
    useArrayPolymorphism = true
))
6
6
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
6
6

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?