Protobuf → Kotlin コンバーター
.proto スキーマを貼り付けると、適切な型・camelCase のフィールド・デフォルト値付きの Kotlin data class が得られます。
入力(.proto スキーマ)
出力(Kotlin)
このツールでできること
Protocol Buffers スキーマがあって — バックエンドチームから渡されたものかもしれないし、サードパーティ API の契約かもしれない — それに対応する型付きの形が必要な Kotlin コードベースがある。Android アプリが gRPC バックエンドを呼ぶケース、あるいはサーバーサイド Kotlin が JSON エンコードの Protobuf メッセージをパースするケース。data class の形だけで済むのに grpc-kotlin のフル codegen パイプラインを組むのはやり過ぎ — 貼り付けて、コピーして、配置するだけで済みます。
型マッピングは Kotlin のイディオムに従います: string → String、bool → Boolean、bytes → ByteArray、int32/sint32/fixed32 → Int、int64/sint64/fixed64 → Long、double → Double、float → Float。repeated T はデフォルト emptyList() 付きの List<T> に、map<K, V> はデフォルト emptyMap() 付きの Map<K, V> になります。単一のネストされたメッセージフィールドはデフォルト null の nullable(?)— proto3 の has-value セマンティクスに合わせています。
フィールド名は proto の snake_case から Kotlin の camelCase へ変換されます(order_id → orderId)— 公式の Kotlin スタイルに基づく標準的な Kotlin コーディング規約です。クラス名と enum 名は PascalCase のままです。各 enum は Int のバッキング値を持つ enum class になります。変換はすべてブラウザ内で完結します — あなたの .proto はページから出ません。
使い方
3 ステップ。出力はそのまま貼り付けられる Kotlin です。
.proto スキーマを貼り付ける
左のエディタにスキーマを置きます。先頭の syntax = "proto3"; はあっても無くても構いません。ネストされた message ブロック、enum 宣言、oneof、map<K, V>、フィールドオプションすべてに対応しています。
Kotlin のコーディング規約はプロパティに camelCase を好みます — コンバーターはそれを行います。元の snake_case 名のままが良ければ(一部のシリアライズライブラリはフィールド名の完全一致を要求します)、出力で find-replace してください。
Kotlin の出力を読む
右側: 各メッセージはすべてのプロパティにデフォルト値付きの data class になります。各 enum は enum class(val value: Int) になり、wire フォーマットをラウンドトリップできます。トップレベルのみ(ネストなし)— 1 ファイルに入れるのも分割するのも楽です。
プロジェクトに組み込む
ファイルをプロジェクトに置き、package 宣言を追加して import します。Android や JVM 上の本物の gRPC コードでは、marshal メソッドとスタブを得るために結局 grpc-kotlin codegen を回したくなるはずです。この出力は型付きの JSON ハンドリング、構造体スケッチ、レビュー用です。
本当に時短になる場面
バックエンドの .proto から Android の型をスケッチする
Android アプリが gRPC バックエンドと通信する。.proto の所有はバックエンドチーム。codegen を組まずに ViewModel を型付けするための data class の形が欲しい。貼り付けて Models.kt に落とせば、もう型付き完了です。
サーバーサイド Kotlin が JSON エンコードの Protobuf をパースする
サーバーサイド Kotlin(Ktor / Spring Boot)が proto3 JSON エンコーディングに従う JSON を消費する。一致する data class が必要です。.proto を貼り付け、Kotlin 出力をコピーし、お好みのシリアライザに繋ぐだけ。
Protobuf API の変更レビュー
チームメイトがメッセージにフィールドを追加した。新しい .proto を貼り付け、Kotlin 出力を現在の Models.kt と diff し、ツールチェーン全体を立ち上げずに焦点を絞ったレビューを残せます。
使い捨てスクリプトと素早いプロトタイプ
gRPC-gateway を叩く 50 行の Kotlin スクリプト。そのために grpc-kotlin と protoc を組むのはやり過ぎ。ここで data class を生成して放り込みます。
よくある質問
これは protoc-gen-kotlin の代わりですか?
いいえ。本物の codegen は marshal/unmarshal メソッド、ディスクリプタ、gRPC のスタブを生成します。このツールは data class の形だけを出力します。プロダクションの gRPC コードには grpc-kotlin を回してください。これはスケッチ、JSON のパース、レビュー、使い捨てスクリプト用です。
単一のメッセージフィールドが nullable なのはなぜ?
proto3 ではメッセージフィールドに「has value」セマンティクスがあり、未設定があり得ます。最も綺麗な Kotlin 同等表現はデフォルト null の nullable プロパティです。データが常にこれらのフィールドを埋めると分かっているなら、? とデフォルトを外してください — シンプルな find-replace です。
uint32 と uint64 はどう扱われますか?
両方とも符号付きの型(Int と Long)にマップされます。Kotlin には 1.5 以降に安定版の UInt と ULong がありますが、符号付きの方が既存のシリアライズライブラリやほとんどの Android コードベースとの相性が良いです。符号なしのバリアントが特に必要なら、出力で差し替えてください。
enum はどのように出力されますか?
各 enum は enum class WithValue(val value: Int) になり、wire フォーマットの整数を保持できます。各値には元の proto 名(例: ORDER_STATUS_PENDING)が付きます — Kotlin の enum エントリは慣例的に SCREAMING_SNAKE_CASE なので、これと一致します。
フィールド名はどう変換されますか?
Kotlin のコーディング規約に従って snake_case → camelCase。order_id は orderId に、customer_name は customerName になります。クラスと enum の名前は proto そのままの PascalCase です。
ネストされたメッセージは扱えますか?
はい — ネストされた message ブロックは出力でトップレベルの data class 宣言に平坦化されます。ファイルを読みやすく保ち、複数ファイルへの分割も楽です。Kotlin のネストされたクラスが好みなら、手で包んでください。
関連ツール
Protobuf と Kotlin を扱っているなら、これらと相性が良いです: