Kotlin Serializationの使い方を詳しく調べてみた

# はじめに
TechBoosterの書籍でKotlin Serializationが少し触れられていたのですが、現在開発中のプロジェクトで利用できそうだったため、もう少し詳しく調べてみることにしました。

# Kotlin Serializationとは
- シリアライザ・デシリアライザである（コード自動生成用のコンパイラプラグインとシリアライズ用のランタイムライブラリの構成）
- JSON, CBOR, Protobufの３つのフォーマットをサポートし、さらに[有志が作成したアドオン](https://github.com/Kotlin/kotlinx.serialization/blob/master/formats/README.md)を使えばHOCON, YAMLも使える
- Kotlin/JVM, Kotlin/JS, Kotlin/Nativeプラットフォームをサポート
- リフレクションを使用しない　ー＞ **リフレクション使用しない分速い！**　<br>（MoshiやGsonなどのパーサーはJsonキーとプロパティを紐付ける際などにリフレクションを使用している）


# インストール手順
- 今回はAndroidを前提にしているのでその他のプラットフォーム用の設定は公式参照のこと

```gradle:build.gradle

buildscript {
    ext.kotlin_version = '1.3.20'
    repositories { jcenter() }

    dependencies {
        classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
        classpath "org.jetbrains.kotlin:kotlin-serialization:$kotlin_version"
    }
}
```

```gradle:app/build.gradle
apply plugin: 'kotlin'
apply plugin: 'kotlinx-serialization'

// 略

repositories {
    jcenter()
    // artifacts are published to this repository
    maven { url "https://kotlin.bintray.com/kotlinx" }
}

dependencies {
    implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"
    implementation "org.jetbrains.kotlinx:kotlinx-serialization-runtime:0.10.0"
}
```

# 使い方

```kotlin
import kotlinx.serialization.*
import kotlinx.serialization.json.Json

@Serializable
data class Data(val a: Int, @Optional val b: String = "42")

fun main(args: Array<String>) {
    // Serializableアノテーションを付けた場合、オブジェクトを渡すだけでOK
    val jsonData = Json.stringify(Data(42))
    // コレクション等も拡張関数serializerを使うことで利用可能
    val jsonList = Json.stringify(Data.serializer().list, listOf(Data(42)))
    println(jsonData) // {"a": 42, "b": "42"}
    println(jsonList) // [{"a": 42, "b": "42"}]

    // 文字列をパースするときも簡単！
    val obj = Json.parse<Data>("""{"a":42}""")
    println(obj) // Data(a=42, b="42")

    // unquotedはフォーマットからダブルクォーテーションを外す
    assertEquals("{a:1, b:42}", Json.unquoted.stringify(Data(1)))
    assertEquals(Data(1), Json.unquoted.parse<Data>("{a:1, b:42}"))
}

```
引用元: https://github.com/Kotlin/kotlinx.serialization#quick-example

# アノテーションについて
|アノテーション|概要|
|---|---|
|Serializable|シリアライズしたいカスタムクラスに付けることでシリアライゼーションできる|
|Optional|必須ではないパラメータに付ける。付けない場合はエラーになる|
|SerialName|Jsonキー名が異なる場合に付ける|
|Transient|Jsonで扱わないプロパティを定義したい場合に使用する。Jsonにこのプロパティが存在していた場合エラーになる|
|SerialInfo|アノテーションクラスを定義するためのアノテーション。<br>プロパティにタグなどの情報をもたせることが出来て、エンコーダー内でタグをもとに条件分岐などに利用できる。<br>[Protobuf](https://github.com/Kotlin/kotlinx.serialization/blob/bb6e21e2c05cf6fa7d9a1b7f0c401d0afe726eda/runtime/common/src/test/kotlin/kotlinx/serialization/protobuf/SampleClasses.kt)などで利用する|

## アノテーションの使い方
               
```kotlin

// シリアライズしたいクラスに付与
@Serializable
data class Data(
   val a: Int,
   // 必須パラメーターではない場合に付ける
   @Optional
   val b: String = “42”,
   // jsonキー名がcでプロパティ名とことなる場合
   @SerialName("c")
   val d: String
)

```

# カスタムシリアライザ
- シリアライザを自作することも可能。このサンプルは日付を扱う例

```kotlin
@Serializer(forClass = Date::class)
object DateSerializer: KSerializer<Date> {
    private val df: DateFormat = SimpleDateFormat("dd/MM/yyyy HH:mm:ss.SSS")

    override val descriptor: SerialDescriptor =
        StringDescriptor.withName("WithCustomDefault")

    override fun serialize(output: Encoder, obj: Date) {
        output.encode(df.format(obj))
    }

    override fun deserialize(input: Decoder): Date {
        return df.parse(input.decode())
    }
}
```
引用元: https://github.com/Kotlin/kotlinx.serialization/blob/master/docs/custom_serializers.md#external-serializers-for-library-classes

# 終わりに
いかがでしたでしょうか？皆さんもKotlin Serializationを使って快適なシリアライゼーション生活を。