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

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

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

* kotlinx.serialization 0.20.0 の変更点はこちら
    * https://github.com/Kotlin/kotlinx.serialization/blob/master/CHANGELOG.md#0200--2020-03-04

# SerialDescriptor の変更

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

```kotlin
// 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 形式へ書き換えます。

```kotlin
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 型が定義されています。

```kotlin
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 へ移動した機能があります。

```kotlin
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
```

↓

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

---

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

↓

```kotlin
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 がもとの設定です。

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

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

```kotlin
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))'
```

↓

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

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

```kotlin
Json(JsonConfiguration.Stable.copy(
    ignoreUnknownKeys = true,
    isLenient = true,
    serializeSpecialFloatingPointValues = true,
    useArrayPolymorphism = true
))
```