シリアライゼーションとは、オブジェクトまたはデータ構造を、ネットワーク送信やファイル保存に適したシーケンシャル形式に変換するプロセスです。逆のプロセスであるデシリアライゼーションは、データを元の状態に復元します。MDN Web Docsによると、シリアライゼーションはあらゆるプロセス間通信に必須です。シリアライゼーションは、REST API、キャッシュ、アプリケーションコンポーネント間のデータ交換の基礎となります。
ポイント
シリアライゼーションとは、RAM上にあるオブジェクトを、ネットワークで送信したり、ファイルに保存したり、別のプロセスに渡したりできるように、バイトや文字の一連のシーケンスに変換するプロセスです。シリアライゼーションがなければ、ネットワーク通信、状態ペーシステンス、プロセス間矛通信は不可能です。
シリアライゼーションには2つの対になるプロセスがあります。正方向のプロセス(シリアライゼーション)はデータを送信用形式にパッケージングします。逆方向のプロセス(デシリアライゼーション)はデータをオブジェクトに復元します。デシリアライゼーションはセキュリティに重要です: 不正な入力データはアプリに脆弱性を引き起こす可能性があります。
モバイルアプリ開発では、シリアライゼーションはあらゆる場面で使われます: サーバへのリクエスト送信とレスポンス処理、画面回転時のアプリ状態保存、ディスクへのデータキャッシュ、Intent(Android)やSegue(iOS)を介した画面間データ転送などです。
シリアライゼーションフォーマットは、テキスト型とバイナリ型に分けられます。テキスト型(JSON、XML)は人間が読め、表示にツールが不要です。バイナリ型(Protobuf、FlatBuffers、MessagePack)はより可簡減されており高速ですが、デシリアライゼーションなしでは読めません。フォーマットの選択は、パフォーマンスとデバッグのやりやすさのトレードオフです。
JSON、XML、Protobufの他に、専門フォーマットもあります: GoogleのFlatBuffers(ゲームやAR向け)、MessagePack(JSONの可簡減バイナリ代替)、ApacheのAvro(Kafka上のビッグデータ向け)、YAML(コメントをサポートする設定フォーマット)。
| フォーマット | 種類 | スキーマ | サイズ | 速度 |
|---|---|---|---|---|
| JSON | テキスト | 任意 | 中程度 | 中程度 |
| XML | テキスト | XSD | 大きい | 低い |
| Protobuf | バイナリ | 必須 | 小さい | 高い |
| FlatBuffers | バイナリ | 必須 | 小さい | 最高 |
| MessagePack | バイナリ | なし | 小さい | 高い |
| Avro | バイナリ | JSON Schema | 小さい | 高い |
モバイルプラットフォームでのシリアライゼーションには、狭い帯域幅、弱いプロセッサ、画面回転時の状態保存といった固有の課題があります。AndroidではGson、Moshi、Kotlinx Serializationが使われます。iOSでは、Codable、JSONSerialization、PropertyListEncoderが使われます。適切なライブラリの選択はアプリのパフォーマンスに大きく影響します。
Kotlinx Serializationは、Kotlin Multiplatform Mobile向けのJetBrainsによる現代的なライブラリです。JSON、Protobuf、CBOR、カスタムフォーマットをサポートします。Kotlin Serializationプラグインを通じてコンパイル時にコード生成が行われ、リフレクションを使用せずに高いパフォーマンスを実現します。
Kotlinx Serializationライブラリは、クラスに@Serializable注釈を付け、コンパイラプラグインでシリアライザを生成します。これにより、高いパフォーマンスと型の安全性が保証されます。デフォルトのフォーマットはJSONですが、他のフォーマットも追加モジュールによってサポートされます。
import kotlinx.serialization.Serializable
import kotlinx.serialization.json.Json
import kotlinx.serialization.encodeToString
import kotlinx.serialization.decodeFromString
@Serializable
data class Project(
val id: Int,
val name: String,
val platforms: List<String>,
val active: Boolean
)
val json = Json {
prettyPrint = true
ignoreUnknownKeys = true
encodeDefaults = true
}
fun main() {
val project = Project(1, "MobileApp",
listOf("Android", "iOS"), true)
// シリアライズ
val jsonString = json.encodeToString(project)
// デシリアライズ
val restored = json.decodeFromString<Project>(jsonString)
}
Codableプロトコルは、Swiftの組み込みシリアライゼーション機構です。これはEncodable(シリアライゼーション)とDecodable(デシリアライゼーション)の2つのプロトコルを組み合わせたものです。JSONEncoderとJSONDecoderは、ネスト構造、配列、オプショナル値、CodingKeysによるカスタムキーを自動的に処理します。
import Foundation
struct AppConfig: Codable {
let appName: String
let version: String
let features: [String]
let isProduction: Bool
}
let config = AppConfig(
appName: "MyApp",
version: "2.1.0",
features: ["push", "analytics", "offline"],
isProduction: true
)
let encoder = JSONEncoder()
encoder.outputFormatting = [.prettyPrinted, .sortedKeys]
guard let data = try? encoder.encode(config) else { return }
let jsonString = String(data: data, encoding: .utf8)
シリアライゼーションフォーマットのパフォーマンスは、メッセージサイズ、シリアライゼーション速度、デシリアライゼーション速度の3つの指標で評価されます。モバイルアプリにとって、これらは全て重要です: サイズは帯域幅とロード時間に影響し、速度はインタフェースのレスポンシブなすとアプリの起動時間に影響します。
バイナリ表現により、ProtobufとFlatBuffersが最も良い結果を示します。FlatBuffersは、別途のデシリアライゼーションステップが不要であることが特徴です — データはバイナリバッファから直接読み取られ、変換が不要なため、最小のレイテンシが要求されるゲームやARアプリに理想的です。JSONは、パフォーマンスは悪いものの、その単純さと普遍性により、REST APIで最も人気のあるフォーマットであり続けています。
| シナリオ | 推奨フォーマット | 理由 |
|---|---|---|
| REST API | JSON | 普遍性、可読性、サポート |
| マイクロサービス | Protobuf | 可簡減性、速度、gRPC |
| ゲーム / AR | FlatBuffers | Zero-copy、最小レイテンシ |
| ビッグデータ | Avro | KafkaやHadoopとの互換性 |
| 設定 | YAML | コメント、可読性 |
| Androidレイアウト | XML | プラットフォーム標準 |
1000のユーザーオブジェクトのデータセットでの実践的なテストによると: Protobufは12 KBのメッセージを生成します(JSONは85 KB、XMLは120 KB)。シリアライゼーション時間: Protobufが2 ms、JSONが8 ms、XMLが25 ms。これらの数値により、バイナリフォーマットは、高ロードシステムや帯域幅の狭いモバイルアプリで優先されます。
例では、同じオブジェクトを異なるフォーマットでシリアライゼーションします。これにより、サイズと可読性を視覚的に比較できます。同じUserオブジェクトがJSON、XML、Protobufでシリアライズされます — JSONはXMLよりも可簡減され、Protobufが最も可簡減でありながらも不可読であることがわかります。
JSON — ミニマルな構文、クォート付きのキー、異なるタイプの値。80文字。可読性は高く、視覚的な構造は明確。開発とデバッグの速度が重視されるAPIに適しています。
XML — 各要素が開始タグと終了タグで囲まれています。150文字。可読性は中程度で、構造は正型。ドキュメントワークフローやXSD検証が必要なシステムに適しています。
Protobuf — バイナリ、このデータには32バイト。不可読 — 表示にはデシリアライゼーションが必要。最小のサイズにより、高ロードシステムやモバイルアプリに理想的です。
{
"id": 42,
"name": "IT Sectr",
"email": "team@itsectr.com",
"role": "admin",
"active": true
}
<user>
<id>42</id>
<name>IT Sectr</name>
<email>team@itsectr.com</email>
<role>admin</role>
<active>true</active>
</user>
最善実践は、よくある誤りを避け、プロジェクトに適したシリアライゼーション策略を選ぶのに役立ちます。これらの推奨事項に従うことで、パフォーマンス、セキュリティ、コードの可維護性が向上します。
シリアライゼーションのセキュリティは非常に重要な側面であり、特に信頼できないソースからのデータをデシリアライズする際に重要です。デシリアライゼーション攻撃は、リモートコード実行(RCE)を引き起こす可能性があり、Webアプリやモバイルアプリにおける最も危険な脆弱性の1つです。最もよく知られたケースは、Java SerializableやPython pickleに関連しています。
ProtobufとJSONには、こうした攻撃に対する組み込みの保護機構があります。というのも、これらはデータのみを扱い、任意のオブジェクトを扱わないからです。一方、Java Serializableは、classpathにあるあらゆるクラスを復元できるため、外部ソースからのデータ受け取りには危険です。Androidでは、標準のJava Serializationの代わりにKotlinx SerializationやMoshiを使用することが推奨されます。
追加のセキュリティ対策: 入力データのサイズに制限を設ける、デシリアライゼーション前にスキーマを検証する、HTTPヘッダのContent-Typeを信用しない、許可されたクラスのアローリストを使用する。シリアライゼーションライブラリを定期的に更新すること。脆弱性は定期的に発見され修正されます。
よくある質問
シリアライゼーションはオブジェクトをバイト列に変換しますが、マーシャリングは、型と構造を保ちながら、異なるアドレス空間の間でデータを転送します。マーシャリングは、シリアライゼーションをプロセスの一部として含みますが、参照のエンコーディングやメモリ管理も含むことがあります。
GoogleのFlatBuffersは、zero-copyデシリアライゼーションにより最大の速度を提供します — データは変換なしにバイナリバッファから直接読み取られます。Protobufが2番目、JSONが3番目です。XMLは一般的なものの中で最も遅いフォーマットです。
Kotlinx Serializationは、Kotlinの新規プロジェクトに最適です: コンパイラ生成、Kotlin Multiplatformサポート、null safety。MoshiはJavaプロジェクトに良い選択で、Gsonよりも高性能です。Gsonは最も簡単に始められるライブラリですが、遅く、リフレクションを使用します。
循環参照は、シリアライゼーション中に無限再帰を引き起こします。解決策: 直接のオブジェクト参照の代わりにID参照を使用する、専用のシリアライゼーションアダプタを適用する(例: Jacksonの@JsonIgnore)、または循環を解消するためにデータモデルを再設計する。
はい、特に信頼できないデータのデシリアライゼーションは重要です。デシリアライゼーションの脆弱性は、リモートコード実行を引き起こす可能性があります。推奨事項: 信頼できないソースからのデータをデシリアライズしない、デシリアライゼーション時にクラスのアローリストを使用する、処理前にデータスキーマを検証する。
まとめ
ターンキー方式のモバイルアプリケーションを開発します
IT Sectrは2017年からスタートアップや企業向けにiOS・Androidアプリケーションを開発しています。私たちがご相談に乗り、最適なソリューションをご提案します。