#はじめに
Kotlin Serialization ガイドの目次に基づいて「Kotlin Serialization guide」を訳しています。
なお、翻訳にはDeepLの力を99%借りています。
もし、一緒に「Kotlin Serialization ガイド」の翻訳をして下さる方がいらっしゃいましたら、コメント欄などから連絡をください。
##第2章 ビルトインクラス<原文>
Latest commit 728e220 on 24 Nov 2020版
Kotlin Serialization Guideの第2章です。 すべてのプリミティブ型と文字列に加えて、標準コレクションを含むKotlin標準ライブラリの一部のクラスのシリアライズがKotlin Serializationに組み込まれています。この章ではその詳細を説明します。
目次
プリミティブ
Kotlin Serializationには次の10種類のプリミティブの型があります。
Boolean
, Byte
, Short
, Int
, Long
, Float
, Double
, Char
, String
, そして列挙型(enums
)
そしてこの他に、これらプリミティブな型の組み合わせで構成された型があります。
数字
すべてのタイプの整数と浮動小数点のKotlin数をシリアライズすることができます。
@Serializable
class Data(
val answer: Int,
val pi: Double
)
fun main() {
val data = Data(42, PI)
println(Json.encodeToString(data))
}
フルコードはこちらから取得できます。
JSONでの自然な表現が使われています。
{"answer":42,"pi":3.141592653589793}
実験的な符号なし数字やその他の実験的なインラインクラスは、Kotlin Serializationではまだサポートされていません。
Long型数字
長い整数も直列化できます。
@Serializable
class Data(val signature: Long)
fun main() {
val data = Data(0x1CAFE2FEED0BABE0)
println(Json.encodeToString(data))
}
完全なコードはこちらから取得できます。
デフォルトでは、数値としてJSONにシリアライズされます。
{"signature":2067120338512882656}
文字列としてのLong型数字
先ほどの例で出力されたJSONは、Kotlin/JS上で実行されているKotlin Serializationによって正常にデコードされます。しかし、このJSONをJavaScriptのネイティブメソッドでパースしようとすると、このように切り詰められた結果が得られます。
JSON.parse("{\"signature\":2067120338512882656}")
▶ {signature: 2067120338512882700}
Kotlin Longの完全な範囲はJavaScriptの数値に収まらないため、その精度はJavaScriptで失われてしまいます。一般的な回避策は、JSON の文字列型を使って完全な精度で長い数値を表現することです。このアプローチは、Kotlin の LongAsStringSerializer
によるシリアライズによってオプションでサポートされており、@Serializable
アノテーションを使って指定することができます。
@Serializable
class Data(
@Serializable(with=LongAsStringSerializer::class)
val signature: Long
)
fun main() {
val data = Data(0x1CAFE2FEED0BABE0)
println(Json.encodeToString(data))
}
フルコードはこちらから取得できます。
このJSONはJavaScriptでネイティブに解析され、精度を損なうことなく解析されます。
{"signature":"2067120338512882656"}
「ファイルにシリアライザを指定する」のセクションでは、
LongAsStringSerializer
のようなシリアライザをファイル内のすべてのプロパティに指定する方法を説明します。
列挙型クラス
以下の例に示すように、すべての列挙型クラスは @Serializable
をマークしなくても、すぐにシリアライズ可能です。
// @Serializable annotation is not need for a enum classes
enum class Status { SUPPORTED }
@Serializable
class Project(val name: String, val status: Status)
fun main() {
val data = Project("kotlinx.serialization", Status.SUPPORTED)
println(Json.encodeToString(data))
}
フルコードはこちらから取得することができます。
JSONではenumは文字列としてエンコードされます。
{"name":"kotlinx.serialization","status":"SUPPORTED"}
列挙エントリのシリアル名
enumエントリのシリアル名は、シリアルフィールド名のセクションのプロパティに表示されているのと同じように、SerialNameアノテーションを使ってカスタマイズすることができます。ただし、この場合、列挙クラス全体には @Serializable
アノテーションを付けなければなりません。
@Serializable // required because of @SerialName
enum class Status { @SerialName("maintained") SUPPORTED }
@Serializable
class Project(val name: String, val status: Status)
fun main() {
val data = Project("kotlinx.serialization", Status.SUPPORTED)
println(Json.encodeToString(data))
}
フルコードはこちらから取得することができます。
指定したシリアル名が結果のJSONで使用されるようになりました。
{"name":"kotlinx.serialization","status":"maintained"}
##コンポジット
Kotlin Serializationでは、標準ライブラリにある多くのコンポジット型がサポートされています。
ペアとトリプル
Kotlin標準ライブラリのシンプルなデータクラス Pair と Triple はシリアライズ可能です。
@Serializable
class Project(val name: String)
fun main() {
val pair = 1 to Project("kotlinx.serialization")
println(Json.encodeToString(pair))
}
フルコードはこちらから取得することができます。
{"first":1,"second":{"name":"kotlinx.serialization"}}
Kotlin標準ライブラリのすべてのクラスがシリアル化できるわけではありません。特にrangeとRegexクラスは現在のところシリアライズできません。将来的にはシリアライズのサポートが追加されるかもしれません。
リスト
シリアライズ可能なクラスのListをシリアライズすることができます。
@Serializable
class Project(val name: String)
fun main() {
val list = listOf(
Project("kotlinx.serialization"),
Project("kotlinx.coroutines")
)
println(Json.encodeToString(list))
}
完全なコードはこちらから取得できます。
結果はJSONのリストとして表現されます。
[{"name":"kotlinx.serialization"},{"name":"kotlinx.coroutines"}]
セットとその他のコレクション
Setのような他のコレクションもシリアル化されています。
@Serializable
class Project(val name: String)
fun main() {
val set = setOf(
Project("kotlinx.serialization"),
Project("kotlinx.coroutines")
)
println(Json.encodeToString(set))
}
フルコードはこちらから取得することができます。
Setも他のすべてのコレクションと同様にJSONではリストとして表現されます。
[{"name":"kotlinx.serialization"},{"name":"kotlinx.coroutines"}]
コレクションのデシリアライズ
デシリアライズの間、結果のオブジェクトの型は、ソースコードで指定された静的な型によって決定されます。次の例は、同じ JSON の整数リストを、異なる Kotlin 型の 2 つのプロパティにデシリアライズする方法を示しています。
@Serializable
data class Data(
val a: List<Int>,
val b: Set<Int>
)
fun main() {
val data = Json.decodeFromString<Data>("""
{
"a": [42, 42],
"b": [42, 42]
}
""")
println(data)
}
フルコードはこちらから取得できます。
data.b
プロパティは Set なので、重複していた値が消えてしまいました。
Data(a=[42, 42], b=[42])
マップ
プリミティブまたは列挙キーと任意の直列化可能な値を持つMapを直列化することができます。
@Serializable
class Project(val name: String)
fun main() {
val map = mapOf(
1 to Project("kotlinx.serialization"),
2 to Project("kotlinx.coroutines")
)
println(Json.encodeToString(map))
}
フルコードはこちらから取得することができます。
JSON の Kotlin マップはオブジェクトとして表現されます。JSONではオブジェクトのキーは常に文字列であるため、Kotlinでは数字であってもキーは文字列としてエンコードされます。
{"1":{"name":"kotlinx.serialization"},"2":{"name":"kotlinx.coroutines"}}
キーを合成できないというのは、JSON 固有の制限です。構造化マップのキーを許可するのセクションで示されているように、解除することができます。
ユニットオブジェクトとシングルトンオブジェクト
Kotlin 組み込みの Unit
型もシリアライズ可能です。ユニット
はKotlinのシングルトンオブジェクトであり、他のKotlinオブジェクトと同じように扱われます。
概念的には、シングルトンとはインスタンスが1つしかないクラスのことで、状態がオブジェクトを定義するのではなく、オブジェクトがその状態を定義することを意味します。JSONでは、オブジェクトは空の構造体としてシリアライズされます。
@Serializable
object SerializationVersion {
val libraryVersion: String = "1.0.0"
}
fun main() {
println(Json.encodeToString(SerializationVersion))
println(Json.encodeToString(Unit))
}
フルコードはこちらから取得することができます。
一見無駄に見えるかもしれませんが、これは、Polymorphism.Objectsのセクションで説明されているように、密閉されたクラスのシリアライズを行う際に便利です。
{}
{}
オブジェクトのシリアライズはフォーマット固有のものです。他のフォーマットでは、オブジェクトの完全修飾名を使用するなど、オブジェクトの表現方法が異なる場合があります。
次の章では、シリアライザを取り上げます。