Smile Engineering Blog

ジェイエスピーからTipsや技術特集、プロジェクト物語を発信します

【Kotlin】Kotlin Serialization で JSON をパースする

今回は、Kotlin Serialization を使って JSON をパースする方法を解説します。

なお、ここに掲載しているソースコードは以下の環境で動作確認しています。

  • Android Studio Bumblebee | 2021.1.1 Patch 2
  • JDK 11.0.11
  • Android Gradle Plugin 7.1.2
  • Kotlin 1.6.20
  • Gradle 7.4.2
  • org.jetbrains.kotlin.plugin.serialization 1.6.20
  • org.jetbrains.kotlinx:kotlinx-serialization-json 1.3.2

ライブラリのインポート

最初に、Kotlin Serialization を使用するために必要なライブラリをインポートします。

まず、以下のようにプロジェクトの build.gradle の plugins に Kotlin Serialization のプラグインを追加します。

// Project's build.gradle
plugins {
    id 'org.jetbrains.kotlin.plugin.serialization' version '1.6.20' apply false
}

そして、モジュールの build.gradle の plugins にも Kotlin Serialization のプラグインを追加します。

// Module's build.gradle
plugins {
    id 'org.jetbrains.kotlin.plugin.serialization'
}

後は、モジュールの build.gradle の dependencies に以下を追加します。

// Module's build.gradle
dependencies {
    implementation "org.jetbrains.kotlinx:kotlinx-serialization-json:1.3.2"
}

以上で、ライブラリのインポートは完了です。

データクラスの宣言

ここから、実装に入っていきます。

まず、パースする JSON のフォーマットをデータクラスで宣言する必要があります。今回は、以下のような JSON の読み書きを行ってみます。

{
    "hidden_card": {
        "rank": "6",
        "suit": "SPADES"
    },
    "visible_cards": [
        {
            "rank": "4",
            "suit": "CLUBS"
        },
        {
            "rank": "A",
            "suit": "HEARTS"
        }
    ]
}

上記の JSON をデータクラスで宣言すると、以下のようになります。

@Serializable
data class BlackjackHand(
    @SerialName("hidden_card") val hiddenCard: Card,
    @SerialName("visible_cards") val visibleCard: List<Card>,
)

@Serializable
data class Card(
    val rank: Char,
    val suit: Suit,
)

enum class Suit {
    CLUBS, DIAMONDS, HEARTS, SPADES;
}

Kotlin Serialization で使用するデータクラスには、@Serializable を追加します。また、hidden_cardhiddenCard のように、JSON とデータクラスで名前が異なる場合、データクラスのプロパティに @SerialName を付与して、対応する JSON の名前を指定します。なお、JSON とデータクラスで名前が一致する場合は、@SerialName を省略できます。

以上で、データクラスの宣言は完了です。

JSON からオブジェクトにパースする

Json.decodeFromStringJSON 文字列を渡すと、パースした後のオブジェクトを返してくれます。

val json = """
    {
        "hidden_card": {
            "rank": "6",
            "suit": "SPADES"
        },
        "visible_cards": [
            {
                "rank": "4",
                "suit": "CLUBS"
            },
            {
                "rank": "A",
                "suit": "HEARTS"
            }
        ]
    }
""".trimIndent()
Log.d(TAG, Json.decodeFromString<BlackjackHand>(json).toString())

上記を実行すると Logcat に以下のログが表示され、JSON からオブジェクトにパースが成功していることがわかります。

D/MainActivity: BlackjackHand(hiddenCard=Card(rank=6, suit=SPADES), visibleCard=[Card(rank=4, suit=CLUBS), Card(rank=A, suit=HEARTS)])

オブジェクトから JSON にパースする

逆に、Json.encodeToString にオブジェクトを渡すと、パースした後の JSON を文字列で返してくれます。

val blackjackHand = BlackjackHand(
    Card('6', Suit.SPADES),
    listOf(Card('4', Suit.CLUBS), Card('A', Suit.HEARTS))
)
Log.d(TAG, Json.encodeToString(blackjackHand))

上記を実行すると Logcat に以下のログが表示され、オブジェクトから JSON にパースが成功していることがわかります。

D/MainActivity: {"hidden_card":{"rank":"6","suit":"SPADES"},"visible_cards":[{"rank":"4","suit":"CLUBS"},{"rank":"A","suit":"HEARTS"}]}

参考

Kotlin Serialization Guide - Basic Serialization