#はじめに
「Kotlin Json文字列のserialization 正しい対処できなかったので逃げ対応で対処しました」の記事のとおり、kotlinx.serializationをうまく使えなかったので、少し勉強を始めました。
手始めに、Kotlinブログ kotlinx.serialization 1.0 releasedを見つけたので、概要を知るために翻訳しました。
さらに知りたい場合は、Kotlin Serialization Guideに進めばよさそうです。
なお翻訳にあたってはDeepLの力を99%利用しました。
#Kotlinブログ kotlinx.serialization 1.0 releasedの翻訳
kotlinx.serialization 1.0 released
Sebastian Aigner October 8, 2020
マルチプラットフォームシリアライゼーションライブラリ kotlinx.serialization のバージョン 1.0 のリリースを皆様と共有できることを嬉しく思います。このライブラリの最初の安定版として、私たちはついに本番に対応したと考えることができます!
Androidアプリを書いている場合でも、Kotlin Multiplatform Mobileを使っている場合でも、サーバーサイドサービスを作成している場合でも、Kotlin/JSを使ってWebフロントエンドを構築している場合でも、kotlinx.serializationにはシンプルながらも強力なKotlin APIが搭載されていて、JSONをパースしてタイプセーフなKotlinオブジェクトに変換したり、その逆も可能です。このリリースを記念して、kotlinx.serialization 1.0で提供されている機能のいくつかを簡単に紹介し、他のソリューションとの違いを確認したいと思います。
kotlinx.serialization の舞台裏を独占的に見たいのであれば、ライブラリの設計と動作をより深く掘り下げた Leonid Startsev のトークもチェックしてみてください。
##kotlinx.serialization を使って、初めてのKotlin オブジェクトをシリアライズ/デシリアライズ
一般的に、シリアライズはソフトウェアプロジェクトで頻繁に出てくるタスクです。モバイルアプリやウェブフロントエンドでは、オブジェクトをプレーンテキスト形式でJSONを返すAPIを使用することが多いでしょう。サーバーサイドのアプリケーションやバックエンドサービスでは、JSONを使用してフォーマットされたリクエストを受け入れて応答する必要があります。また、ディスク上に情報を保存したい場合でも、人間が読めるフォーマットとして JSON を使用するのが一般的です。
ご覧のように、Kotlin オブジェクトを (de) serialization するプロセスは、あなたのプロジェクトでも遅かれ早かれ遭遇することになるでしょう。kotlinx.serialization を選択すると、このプロセス全体が非常に簡単になります。ライブラリをプロジェクトに追加した後、基本的な Kotlin オブジェクトを JSON 表現に変換して返すのは、そのクラスに @Serializable アノテーションを付けて、Json オブジェクトに提供されている encodeToString と decodeFromString 拡張関数を使うだけです。
@Serializable
data class User(val name: String, val yearOfBirth: Int)
fun main() {
// Serialization (Kotlin object to JSON string)
val data = User("Louis", 1901)
val string = Json.encodeToString(data)
println(string) // {"name":"Louis","yearOfBirth":1901}
// Deserialization (JSON string to Kotlin object)
val obj = Json.decodeFromString<User>(string)
println(obj) // User(name=Louis, yearOfBirth=1901)
}
もちろん、このようなシリアライズ関連のタスクを実行するために使用できるライブラリは、kotlinx.serializationだけではありません。JVMエコシステムでは、JSONを扱うための他のライブラリが多数存在します。しかし、利用可能な最も人気のある選択肢は必ずしもKotlinファーストではなく、Kotlinマルチプラットフォームのプロジェクトでは全く利用できないかもしれません。それ以上にも、あなたのプロジェクトに kotlinx.serialization を選ぶ素晴らしい理由があります。
##なぜ kotlinx.serialization を選ぶのですか?
kotlinx.serialization に含まれるいくつかの機能やデザインの選択は、他のライブラリとは一線を画しており、一般的にはその機能をより楽しく使うのに役立ちます。そのうちのいくつかを詳しく見てみましょう。
###Kotlin スルー and スルー(Kotlin through and through)
kotlinx.serialization は純粋な Kotlin で書かれているだけでなく、Kotlin/Native や Kotlin/JS を含むすべての Kotlin Multiplatform ターゲットで利用可能です。また、このシリアライズ機能は Kotlin の型システムを念頭に置いて作られています。プロパティにデフォルトのイニシャライザが設定されているデータクラスをシリアライズしようとしている場合でも、シングルトンオブジェクトをシリアライズしようとしている場合でも、一般的なリストをデシリアライズしようとしている場合でも、kotlinx.serializationは常に期待通りの動作をします。これは、複雑なプロジェクトオブジェクトのリスト (データクラスによって記述されている) を JSON 表現に変換し、それを返す具体的な例を見るとよくわかります。
@Serializable
data class Project(
val name: String,
val owner: Account,
val group: String = "R&D"
)
@Serializable
data class Account(val userName: String)
val moonshot = Project("Moonshot", Account("Jane"))
val cleanup = Project("Cleanup", Account("Mike"), "Maintenance")
fun main() {
val string = Json.encodeToString(listOf(moonshot, cleanup))
println(string)
// [{"name":"Moonshot","owner":{"userName":"Jane"}},{"name":"Cleanup","owner":{"userName":"Mike"},"group":"Maintenance"}]
val projectCollection = Json.decodeFromString<List<Project>>(string)
println(projectCollection)
// [Project(name=Moonshot, owner=Account(userName=Jane), group=R&D), Project(name=Cleanup, owner=Account(userName=Mike), group=Maintenance)]
}
ご覧のように、ジェネリックを使ったコレクションの型安全なデシリアライズでさえ、kotlinx.serializationによって期待通りに処理されます。JVM上のコレクションは通常型消去の影響を受けるため、これは確かに一般的ではありません。そのため、他のライブラリでは、このような状況では明示的な型トークンを使用するなどの回避策を使用する必要があります。kotlinx.serializationは、projectCollection の例で見るようにコンパイラプラグインを使用して統合されていて、すぐに使え、思い通りに動作するので、回避策は必要ありません。
初めてアプリケーションを起動する前に可能な限り多くの問題をキャッチできるようにしたいと考えているため、kotlinx.serialization はコンパイル時の安全性にも力を入れています。例えば、上の例で Account クラスを @Serializable と明示的にマークしなかった場合、コンパイル時に「Serializer has not found for type 'Account'」というエラーが発生し、クラッシュを経験する代わりに問題を事前に特定して修正することが容易になります。
###多態性のある(ポリモフィズムな)シリアル化
kotlinx.serialization は、シリアライズするオブジェクトの継承階層を快適かつ安全に扱うことを可能にします。このライブラリは Kotlin 固有の型システムの概念を認識しているので、ポリモーフィックシリアライズを使う最も簡単な方法は、すべてのサブクラスが @Serializable として明示的にマークされている密閉されたクラス階層を構築することです。密閉されたクラス階層はコンパイル時にわかるので、kotlinx.serialization プラグインはこの情報を利用することができ、サブクラスとスーパークラスのシリアライズに必要なコードは簡潔なままです。
@Serializable
data class BroadcastMessage(override val content: String) : Message()
@Serializable
data class DirectMessage(override val content: String, val recipient: String) : Message()
fun main() {
val data: List<Message> = listOf(
DirectMessage("Hey, Joe!", "Joe"),
BroadcastMessage("Hey, all!")
)
val string = Json.encodeToString(data)
println(string)
// [{"type":"DirectMessage","content":"Hey, Joe!","recipient":"Joe"},{"type":"BroadcastMessage","content":"Hey, all!"}]
val obj = Json.decodeFromString<List<Message>>(string)
println(obj)
// [DirectMessage(content=Hey, Joe!, recipient=Joe), BroadcastMessage(content=Hey, all!)]
}
文字列変数を見ればわかるように、kotlinx.serialization は、特定のサブタイプに関する情報を含む JSON オブジェクトにインテリジェントにタイプキーを追加します - この動作を手動で指定する必要はありません。クライアントとサーバの両方を管理している場合、これにより、継承関係を使ってメッセージを簡単に構造化することが可能になります。
封印されたクラスは kotlinx.serialization でポリモーフィックシリアライズを使う最も便利な方法であり、すでに多くのユースケースをカバーすることができますが、実際にはこのライブラリはこれらの閉じた階層を超える機能も提供しています。この機能の詳細については、ガイドのポリモーフィズムのセクションをチェックしてください。
###強力なカスタマイズ性
特に外部システムや API と通信する場合、JSON 形式のメッセージを正確に受け取る形を完全にコントロールできないかもしれません。一方で、通信相手のリモートに受け入れられるように kotlinx.serialization が生成する出力を調整する必要性を感じるかもしれません。
Kotlinx.serialization には豊富な DSL 設定 が付属しており、一般的な入力の扱い方や出力の生成方法を調整したり、プリティプリントを有効にしたり、パースを甘くしたり、未知のキーを無視したりといった一般的な設定を変更したりするために使用することができます。クラスやオブジェクト固有の設定では、アノテーションを使用して動作をカスタマイズすることができます。例えば、フィールドの名前を変更したり (@ SerialName)、シリアライズ処理から除外したり (@ Transient) などです。これらのアノテーションについては、他にも多くのアノテーションがありますが、このガイドでも説明しています。ユースケースが必要であれば、特定のタイプのオブジェクトに対して完全にカスタムのシリアライザを提供することもできます。
これらの機能を組み合わせることで、ライブラリの動作を、シリアル化されたフォーマットの要件や仕様に正確に適合するように設計することができます。
###フレームワークの統合
簡潔なインターフェイスを持つ kotlinx.serialization は、プロジェクトに含まれる他のライブラリに関係なく使用できますが、多くのフレームワークは kotlinx.serialization を使用するための直接統合機能も提供しています。ここではいくつかの例を紹介します。
-
サーバサイドフレームワークとして Ktor を使用している場合は、kotlinx.serialization との公式な統合機能をコンテンツネゴシエーションと一緒に使用することで、Kotlin オブジェクトを使って直接リクエストを受信して応答することが可能になります。Kotlin Multiplatform プロジェクトで利用できる Ktor-Clients 対応のものは、kotlinx.serialization を介した JSON ペイロード処理も提供しています。
-
Spring MVC は最近 kotlinx.serialization のサポートを追加し、Sébastien Deleuze のおかげで Spring WebFlux にも同様の統合が提案されています。
-
Http4k は、kotlinx.serialization を使用して HTTP メッセージとの間でマーシャルを行うためのファーストクラスのサポートを提供します。
-
Fuel は、Android HTTP クライアントで kotlinx.serialization を使用するための拡張パッケージを提供します。
-
MongoDB を使っている場合、KMongo ライブラリは kotlinx.serialization を通じてオブジェクトマッピングを提供しています。
-
Retrofit 2を使ってHTTP APIをKotlinのインターフェイスにする場合は、Jake Whartonによるserialization converterを使って、kotlinx.serializationと統合することができます。
kotlinx.serialization と直接統合するサードパーティのプロジェクトが増えていることに非常に興奮しています。そして今、私たちのライブラリは生産可能な状態になったので、すぐにこのような統合がもっとたくさん見られることを期待しています。
###マルチフォーマットの未来
バージョン1.0では、JSONの操作に関連するすべての機能が安定しており、本番に対応しています - しかし、kotlinx.serializationはこれで終わりではありません! JSONに加えて、チームはHOCON、ProtoBuf、CBOR、およびPropertiesシリアライゼーションフォーマットの追加サポートに取り組んでいます。これらのフォーマットはまだ設計・開発中であり、安定性やプラットフォームとの互換性にはばらつきがありますが、すでに試してみることができます。これらのフォーマットは別の成果物として利用可能であり、フォーマットの状態の簡単な説明とともにガイドの中で見つけることができます。
BSON、XML、YAML のようなコミュニティが管理するフォーマットもチームが公式に取り組んでいるフォーマットと並んで存在します - しかし、これらはコミュニティのメンバーによって作成され、管理されていることに注意してください。カスタムフォーマットの作成はまだ実験的な機能であり、変更を壊す可能性があるため、メンテナによる更新が遅れる可能性があります。
ここまでで、kotlinx.serialization を快適に使うためのいくつかの機能を紹介してきましたが、あなたの現在の (あるいは次の) プロジェクトのためにライブラリを選ぶべき理由がお分かりいただけたかと思います - 手っ取り早いです!
###プロジェクトにkotlinx.serializationを追加する
プロジェクトで kotlinx.serialization を使い始めるには、コンパイラプラグインとランタイムライブラリをプロジェクトに追加するだけです。build.gradle(.kts) のプラグインブロックに以下のエントリを追加します。
plugins {
kotlin("plugin.serialization") version "1.4.0"
}
次に、ランタイムライブラリの依存関係を build.gradle(.kts) ファイルの依存関係ブロックに追加します。Kotlin マルチプラットフォームプロジェクトで作業している場合は、共通のターゲット依存関係ブロックに依存関係を追加すれば十分です - プラットフォーム固有の依存関係はすべて自動的に追加されます。
dependencies {
implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:1.0.0")
}
これで、kotlinx.serializationを使い始める準備ができました。このブログ記事に含まれているサンプルを試してみたり、自分のユースケースを試してみたり、ガイドに含まれているサンプルを使って遊んでみたりしてください。
###より多くのことを学び、フィードバックする
kotlinx.serialization の簡単な概要をお楽しみいただけたでしょうか。常に最新のインストール方法を含む詳細な情報を得るためには、GitHub のホームにアクセスしてください。kotlinx.serialization ガイドには、ライブラリの基本的な機能と高度な機能についての詳細な情報が含まれており、このブログ記事で紹介したトピックの多くをより詳細にカバーしています。ライブラリの使い方に問題が生じた場合は、プロジェクトの issue tracker や Kotlin Slack の #serialization チャンネルに助けを求めることができます。
以前に kotlinx.serialization を使用していた場合は、変更点やプロジェクトを安定版にアップグレードする方法を確認するために changelog と migration guide を使用してください。
Kotlin 1.4 オンラインイベント期間中に行われた Leonid Startsev 氏による kotlinx.serialization トークをご覧ください。
https://youtu.be/Azi57n59ICM
###チームからの感謝の言葉
フィードバックをくださった方、プルリクエストを提出してくださった方、1.0 以前の kotlinx.serialization を使用してくださった方、ライブラリに何らかの形で貢献してくださった方、すべての方に「ありがとう」と言いたいと思います。皆様からのご意見は、チームが堅牢で使いやすく、Kotlin を第一としたマルチプラットフォームのシリアライゼーションライブラリを提供する上で非常に貴重なものでした。最初の安定版リリースの前に 700 以上の問題を報告していただいたおかげで、この最初の安定版リリースの前にバグを潰したり、設計のしわ寄せを取り除いたりすることができました。私たちがプロジェクトを進化させていく中で、皆さんの継続的なサポートとフィードバックを頼りにして、改善と革新を続けていけることを願っています。というわけで。それでは皆さん、ありがとうございました。