Home About Contact
Kotlin , Kotlin Script , JSON

Kotlin Script で Serialization JSON を使う

Kotlin の Serialization の JSON を Kotlin Script で使う方法を調べた。

注意点としては、 スクリプト実行時に -Xplugin オプションを追加する必要がある。

see also: https://stackoverflow.com/questions/68202117/how-do-i-apply-a-plugin-in-a-kts-kotlin-script-file

環境:

$ kotlin -version
Kotlin version 1.9.22-release-704 (JRE 17.0.10+7-Ubuntu-122.04.1)

Serialization なしで JSON を読む

まずはウォーミングアップとして。

json.main.kts

@file:Repository("https://repo1.maven.org/maven2/")
@file:DependsOn("org.jetbrains.kotlinx:kotlinx-serialization-json-jvm:1.6.3")

import kotlinx.serialization.json.Json
import kotlinx.serialization.json.JsonElement
import kotlinx.serialization.json.JsonArray
import kotlinx.serialization.json.jsonObject

val jsonString = """{
  "pokemons": [
    {"name": "Pikachu", "type": "Electric"},
    {"name": "Raichu",  "type": "Electric"},
    {"name": "Squirtle","type": "Water"}]}"""

val rootElement: JsonElement = Json.parseToJsonElement(jsonString)
val pokemons: JsonArray = rootElement.jsonObject["pokemons"] as JsonArray
pokemons.forEach { pokemon->
    val name = pokemon.jsonObject["name"]
    val type = pokemon.jsonObject["type"]
    println("- $name ($type)")
}

実行します。

$ kotlin json.main.kts
- "Pikachu" ("Electric")
- "Raichu" ("Electric")
- "Squirtle" ("Water")

できました。

Serialization を使って JSON を読む

JSONを用意したデータクラスへ変換します。 (デコード, デシリアライズ?またはインフレートすると言うべきか。) そのためのデータクラス PokemonPokemons を用意。

import kotlinx.serialization.Serializable

@Serializable
data class Pokemon(val name: String, val type: String)

@Serializable
data class Pokemons(val pokemons: List<Pokemon>)

さらに decodeFromStringjsonStringPokemons へ変換するコードを追加。 ( decodeFromString をインポートしておく必要があります。)

import kotlinx.serialization.decodeFromString

val pokemons = Json.decodeFromString<Pokemons>(jsonString)
println(pokemons)

実行します。

$ kotlin -Xplugin=$HOME/.local/kotlinc/lib/kotlinx-serialization-compiler-plugin.jar json.main.kts
Pokemons(pokemons=[Pokemon(name=Pikachu, type=Electric), Pokemon(name=Raichu, type=Electric), Pokemon(name=Squirtle, type=Water)])

-Xplugin で指定するパス:

$HOME/.local/kotlinc/lib/kotlinx-serialization-compiler-plugin.jar

は環境に合わせて変更してください。

実際のところ、この手順で作業したときに、(事情はよくわからないのだが、おそらくキャッシュしているとかかな?) 一回目はうまく動かない。 @Serialization のアノテーションをいったんはコメントアウトして実行して(当然エラーになる)、 再度コメントアウト外して実行したら作動しました。

これはいやな感じです。 スクリプトで Serialization するのは避けた方がよいかもしれません。 素直に Gradle のプロジェクトをつくるべきか。

まとめ

完成したコード json.main.kts:

@file:Repository("https://repo1.maven.org/maven2/")
@file:DependsOn("org.jetbrains.kotlinx:kotlinx-serialization-json-jvm:1.6.3")

import kotlinx.serialization.json.Json
import kotlinx.serialization.json.JsonElement
import kotlinx.serialization.json.JsonArray

import kotlinx.serialization.Serializable
import kotlinx.serialization.decodeFromString

@Serializable
data class Pokemon(val name: String, val type: String)

@Serializable
data class Pokemons(val pokemons: List<Pokemon>)


val jsonString = """{
  "pokemons": [
    {"name": "Pikachu", "type": "Electric"},
    {"name": "Raichu",  "type": "Electric"},
    {"name": "Squirtle","type": "Water"}]}"""

/*
val rootElement: JsonElement = Json.parseToJsonElement(jsonString)
val pokemons: JsonArray = rootElement.jsonObject["pokemons"] as JsonArray
pokemons.forEach { pokemon->
    val name = pokemon.jsonObject["name"]
    val type = pokemon.jsonObject["type"]
    println("- $name ($type)")
}
*/

val pokemons = Json.decodeFromString<Pokemons>(jsonString)
println(pokemons)