KotlinJava

JSONの特定の値に応じてパースする型を変えたい

JSONのtypeというパラメータによって、使うフィールドが異なる場合にパッと思いつくやり方は以下かなと思います。

data class User(
    // ユーザーのタイプを表す 'free' or 'payed'
    val type: String,
    // どちらの型でも共通
    val name: String,
    // freeの場合のみ存在する
    val trialEndAt: Date,
    // payedの場合のみ存在する
    val purchasedAt: Date,
)
{
  "users": [
    {
      "type": "free",
      "name": "John",
      "trialEndAt": '2022-02-02T19:00:00+09:00'
    },
    {
      "type": "payed",
      "name": "Alice",
      "purchasedAt": '2022-01-22T19:00:00+09:00'
    }
  ]
}

@JsonTypeInfo@JsonSubTypes を使って型を振り分ける

@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, include = JsonTypeInfo.As.PROPERTY, property = "type") // “type” というJSONのキーで型を判別する
@JsonSubTypes(  // “type”の値に応じてどの型にパースするか
    value = [
        JsonSubTypes.Type(value = User.Free::class, name = "free"),
        JsonSubTypes.Type(value = User.Payed::class, name = "payed"),
    ]
)
sealed class User(val name: String) { // type はフィールドには入れない
    data class Free(val trialEndAt: Date) : User()
 
    data class Payed(val purchasedAt: Date) : User()
}

普段は継承をあまり使いたくないが、 sealed class でスコープを限定することで使いやすくした。 継承にする必要はなく別クラスに定義しても問題ないはず。

参考

Kotlin with Jackson: Deserializing Kotlin Sealed Classes | by Sergii Prodan | Medium JsonDeserializerを使って空の時に型が配列になるプロパティに対応する - Qiita Jacksonで独自のJSONシリアライズをする | GROUP DEV BLOG | TECHNO DIGITAL Jackson使い方メモ - Qiita Parse Snake case JSON in Spring Boot | by Bhanu Chaddha | Medium 備忘録的なblog: Jacksonでsnake caseのキーをlower camel caseのプロパティーにデシリアライズする Jackson overcoming underscores in favor of camel-case