今回は、Moshi を使って 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
- KSP 1.6.20-1.0.4
- com.squareup.moshi 1.13.0
ライブラリのインポート
最初に、Moshi を使用するために必要なライブラリをインポートします。
まず、今回は KSP を使用するため、KSP をインポートします。プロジェクトの build.gradle の plugins
に com.google.devtools.ksp
を追加します。
// Project's build.gradle plugins { id 'com.google.devtools.ksp' version '1.6.20-1.0.4' apply false }
そして、モジュールの build.gradle の plugins
にも com.google.devtools.ksp
を追加します。
// Module's build.gradle plugins { id "com.google.devtools.ksp" }
これで、KSP を使用できるようになります。
後は、Moshi を使用するためにモジュールの build.gradle の dependencies
に以下を追加します。
// Module's build.gradle dependencies { implementation "com.squareup.moshi:moshi:1.13.0" ksp "com.squareup.moshi:moshi-kotlin-codegen:1.13.0" }
以上で、ライブラリのインポートは完了です。
データクラスの宣言
ここから、実装に入っていきます。
まず、パースする JSON のフォーマットをデータクラスで宣言する必要があります。今回、以下のような JSON の読み書きを行ってみます。
{ "hidden_card": { "rank": "6", "suit": "SPADES" }, "visible_cards": [ { "rank": "4", "suit": "CLUBS" }, { "rank": "A", "suit": "HEARTS" } ] }
上記の JSON をデータクラスで宣言すると、以下のようになります。
@JsonClass(generateAdapter = true) data class BlackjackHand( @Json(name = "hidden_card") val hiddenCard: Card, @Json(name = "visible_cards") val visibleCard: List<Card>, ) @JsonClass(generateAdapter = true) data class Card( val rank: Char, val suit: Suit, ) enum class Suit { CLUBS, DIAMONDS, HEARTS, SPADES; }
Moshi で使用するデータクラスには、@JsonClass(generateAdapter = true)
を追加します。また、hidden_card
と hiddenCard
のように、JSON とデータクラスで名前が異なる場合、データクラスのプロパティに @Json
を付与して、対応する JSON の名前を指定します。なお、JSON とデータクラスで名前が一致する場合は、@Json
を省略できます。
以上で、データクラスの宣言は完了です。
インスタンスの生成
val moshi = Moshi.Builder().build() val jsonAdapter = moshi.adapter(BlackjackHand::class.java)
上記 1 行目の Moshi.Builder().build()
にて Moshi のインスタンスを生成します。そして、2 行目で Moshi のインスタンスに JSON のデータクラスを渡して、JsonAdapter を生成します。この JsonAdapter を使って、JSON をパースします。
JSON からオブジェクトにパースする
さきほど生成した JsonAdapter を使って JSON からオブジェクトにパースします。JsonAdapter#fromJson に JSON 文字列を渡すと、パースした後のオブジェクトを返してくれます。
val json = """ { "hidden_card": { "rank": "6", "suit": "SPADES" }, "visible_cards": [ { "rank": "4", "suit": "CLUBS" }, { "rank": "A", "suit": "HEARTS" } ] } """.trimIndent() val blackjackHand = jsonAdapter.fromJson(json) Log.d(TAG, blackjackHand.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 にパースすることも可能です。JsonAdapter#toJson にオブジェクトを渡すと、パースした後の JSON を文字列で返してくれます。
val blackjackHand = BlackjackHand( Card('6', Suit.SPADES), listOf(Card('4', Suit.CLUBS), Card('A', Suit.HEARTS)) ) val json = jsonAdapter.toJson(blackjackHand) Log.d(TAG, json)
上記を実行すると Logcat に以下のログが表示され、オブジェクトから JSON にパースが成功していることがわかります。
D/MainActivity: {"hidden_card":{"rank":"6","suit":"SPADES"},"visible_cards":[{"rank":"4","suit":"CLUBS"},{"rank":"A","suit":"HEARTS"}]}