KotlinシリアライゼーションのJSON命名戦略を設定する

snake_case、camelCase、kebab-caseのJSONキーをKotlinの命名戦略オプションで処理する方法を学びます。グローバル戦略とフィールド単位の@SerialNameオーバーライドを解説します。

Serialization

詳細な説明

KotlinのJSON命名戦略

JSON APIは一般的にsnake_caseを使用し、KotlinはcamelCaseを使用します。すべてのプロパティに@SerialNameを追加する代わりに、グローバル命名戦略を設定できます。

kotlinx.serialization命名戦略 (1.6.0+)

val json = Json {
    namingStrategy = JsonNamingStrategy.SnakeCase
}

@Serializable
data class UserProfile(
    val userId: Int,          // "user_id"にマッピング
    val firstName: String,    // "first_name"にマッピング
    val lastName: String,     // "last_name"にマッピング
    val isActive: Boolean,    // "is_active"にマッピング
    val createdAt: String     // "created_at"にマッピング
)

Snake Case変換の仕組み

戦略はcamelCaseの境界で分割し、アンダースコアで結合します:

Kotlinプロパティ JSONキー
userId user_id
firstName first_name
isActive is_active
apiURL api_u_r_l(注意!)

個別フィールドのオーバーライド

グローバル戦略があっても、特定のフィールドには@SerialNameが優先されます:

val json = Json {
    namingStrategy = JsonNamingStrategy.SnakeCase
}

@Serializable
data class Config(
    val apiVersion: String,               // "api_version"(自動)
    @SerialName("APIKey") val apiKey: String  // "APIKey"(オーバーライド)
)

Gsonの命名ポリシー

val gson = GsonBuilder()
    .setFieldNamingPolicy(FieldNamingPolicy.LOWER_CASE_WITH_UNDERSCORES)
    .create()

MoshiとKotlinJsonAdapterFactory

Moshiには組み込みの命名戦略がありません。フィールドごとに@Json(name = "...")を使用します:

data class User(
    @Json(name = "user_id") val userId: Int,
    @Json(name = "first_name") val firstName: String
)

どのアプローチを選ぶか?

シナリオ 推奨
すべてのフィールドがsnake_caseに従う グローバルSnakeCase戦略
命名規則が混在 フィールド単位の@SerialName
不整合のあるレガシーAPI フィールド単位のアノテーション
マルチプラットフォームプロジェクト kotlinx.serializationグローバル戦略

よくある落とし穴:頭字語

連続する大文字は予期しないsnake_case結果を生む可能性があります。apiURLhtmlParserのようなプロパティでは、出力をテストするか、予期しない結果を避けるために明示的な@SerialNameを使用してください。

ユースケース

PythonやRubyバックエンドからKotlinベースのサービスに移行する場合、JSONコントラクトはsnake_caseを使用します。グローバル命名戦略により数百の@SerialNameアノテーションを回避し、KotlinコードをcamelCaseプロパティで慣用的に保てます。

試してみる — JSON to Kotlin

フルツールを開く