【Kotlin/Android】GSONでTypeAdapterを使ってJSONの値を別のデータ型に変換する方法

【Kotlin/Android】GSONでTypeAdapterを使ってJSONの値を別のデータ型に変換する方法

この記事からわかること

  • Android Studio/KotlinライブラリGSON使い方
  • fromJson/toJsonメソッド使い方
  • TypeAdapter任意データ型に変換するには?

index

[open]

\ アプリをリリースしました /

みんなの誕生日

友達や家族の誕生日をメモ!通知も届く-みんなの誕生日-

posted withアプリーチ

参考文献:公式リファレンス:GSON

環境

GSONでJSONの値を別のデータ型に変換する方法

例えば値として0または1を持つJSONの形式があった場合にこれをKotlin内ではBooleanとして扱いたいとします。今回使用するJSON変換ライブラリGSONでは普通に変換するとInt型になってしまうのでこれをカスタムできるように実装していきます。

JSON

{
  "id": "12345",
  "flag": 1
}

Kotlinで扱いたいクラス

data class Example(
    val id: String,
    val flag: Boolean
)

TypeAdapterを使用する

GSONでJSONの値を別のデータ型に変換するにはTypeAdapterを継承したExampleを変換するためのカスタムクラスを用意します。

class ExampleTypeAdapter : TypeAdapter<Example>() {
  
    /** オブジェクトをJSONにエンコードする方法を定義 */
    override fun write(out: JsonWriter, value: Example) {
        // オブジェクトのエンコード開始
        out.beginObject()
        out.name("id").value(value.id)
        out.name("flag").value(if (value.flag) 1 else 0)
        // オブジェクトのエンコード終了
        out.endObject()
    }

    /** JSONをオブジェクトにデコードする方法を定義 */
    override fun read(`in`: JsonReader): Example {
        var id: String? = null
        var flag: Boolean? = null

        // オブジェクトのデコード開始
        `in`.beginObject()
        // hasNext:未処理のデータがあるか
        while (`in`.hasNext()) {
            // nextName():キー名を取得
            when (`in`.nextName()) {
                // nextString():Stringとして読み取り
                "id" -> id = `in`.nextString()
                "flag" -> {
                    // peek():JSONの値を取得
                    flag = when (`in`.peek()) {
                        // データ型によって分岐(念の為複数パターン用意)
                        // Int → 0でない場合はtrue、0の場合はfalse
                        JsonToken.NUMBER -> `in`.nextInt() != 0
                        // Boolean → そのまま
                        JsonToken.BOOLEAN -> `in`.nextBoolean()
                        // String → 文字列が "true"であるかどうかを確認
                        JsonToken.STRING -> {
                            val stringValue = `in`.nextString()
                            stringValue.equals("true", ignoreCase = true)
                        }
                        else -> throw IllegalStateException("期待する値ではなかったよ:" + `in`.peek())
                    }
                }
                // その他のキーはスキップ
                else -> `in`.skipValue() 
            }
        }
        // オブジェクトのデコード終了
        `in`.endObject()

        return Example(
            id = id ?: throw IllegalStateException("Missing 'id' field in JSON"),
            flag = flag ?: throw IllegalStateException("Missing 'flag' field in JSON")
        )
    }
}

続いて作成したTypeAdapterクラスはregisterTypeAdapterを使用して登録しておきます。

val gson: Gson = GsonBuilder()
    .registerTypeAdapter(Example::class.java, ExampleTypeAdapter())
    .create()

あとはGSONを使用して普通にエンコード/デコード処理を実装すれば期待通りの結果になります。

val jsonString = """{"id":"12345","flag":1}"""
val example: Example = gson.fromJson(jsonString, Example::class.java)
Log.d("GSON", example.flag.toString()) // true

val jsonStringFalse = """{"id":"23456","flag":0}"""
val exampleFalse: Example = gson.fromJson(jsonStringFalse, Example::class.java)
Log.d("GSON", exampleFalse.flag.toString()) // false

val json = gson.toJson(example)
Log.d("GSON", json) // {"id":"12345","flag":1}

まだまだ勉強中ですので間違っている点や至らぬ点がありましたら教えていただけると助かります。

ご覧いただきありがとうございました。

searchbox

スポンサー

ProFile

ame

趣味:読書,プログラミング学習,サイト制作,ブログ

IT嫌いを克服するためにITパスを取得しようと勉強してからサイト制作が趣味に変わりました笑
今はCMSを使わずこのサイトを完全自作でサイト運営中〜

New Article

index