KotlinでJSONに対する処理する場合 JavaVM上で実行するコード用であれば、たとえば org.json とか Gson などいろいろなライブラリがありますが、 Kotlin/JS を使って JavaScript に変換して作動させたい場合は、それらのライブラリは(たぶん)使えません。 でも、Kotlin Serialization を使えば、Kotlin で書いたコードもJavaScriptに変換できるので、それを試します。
Kotlin Serialization についてはこの辺からたどっていくと情報が得られます。
まずは kotlin script で試す。
json.main.kts :
@file:Repository("https://repo1.maven.org/maven2/")
@file:DependsOn("org.jetbrains.kotlinx:kotlinx-serialization-json-jvm:1.4.1")
import kotlinx.serialization.json.*
val jsonElement: JsonElement = Json.parseToJsonElement( """{"hello":"world"}""" )
println(jsonElement)
val helloObject: JsonElement? = jsonElement.jsonObject["hello"]
println(helloObject)
val helloContent: String = jsonElement.jsonObject["hello"]?.jsonPrimitive?.contentOrNull?:""
println(helloContent)
実行:
$ kotlinc -script json.main.kts
{"hello":"world"}
"world"
world
はい、できました。
Json, JsonElement しか使っていないと思って、import を修正すると...
import kotlinx.serialization.json.Json
import kotlinx.serialization.json.JsonElement
実行:
$ kotlinc -script json.main.kts
error: unresolved reference: jsonObject (json.main.kts:18:45)
error: unresolved reference: jsonObject (json.main.kts:21:40)
json.main.kts:18:45: error: unresolved reference: jsonObject
val helloObject: JsonElement? = jsonElement.jsonObject["hello"]
^
json.main.kts:21:40: error: unresolved reference: jsonObject
val helloContent: String = jsonElement.jsonObject["hello"]?.jsonPrimitive?.contentOrNull?:""
このようにエラーになります。 たぶん、これは jsonObject などが いわゆる Kotlin Extentions などで実装されているからだと思われますが、詳しくは調べていません。
結局、明示的にインポートした場合に必要となるインポートは以下の通り。
import kotlinx.serialization.json.Json
import kotlinx.serialization.json.JsonElement
import kotlinx.serialization.json.jsonObject
import kotlinx.serialization.json.jsonPrimitive
import kotlinx.serialization.json.contentOrNull
これで作動します。
コード全体 json.main.kts :
@file:Repository("https://repo1.maven.org/maven2/")
@file:DependsOn("org.jetbrains.kotlinx:kotlinx-serialization-json-jvm:1.4.1")
import kotlinx.serialization.json.Json
import kotlinx.serialization.json.JsonElement
import kotlinx.serialization.json.jsonObject
import kotlinx.serialization.json.jsonPrimitive
import kotlinx.serialization.json.contentOrNull
val jsonElement: JsonElement = Json.parseToJsonElement( """{"hello":"world"}""" )
println(jsonElement)
val helloObject: JsonElement? = jsonElement.jsonObject["hello"]
println(helloObject)
val helloContent: String = jsonElement.jsonObject["hello"]?.jsonPrimitive?.contentOrNull?:""
println(helloContent)
ここまでは単にjson をパースしただけで、Serialization というからには、シリアライズやデシリアライズを試そうと思ったのですが、 kotlin script では @Serializable がうまく作動しないようです。
それでは gradle を使って Serialization を Node.js から利用できるのか試します。
プロジェクトディレクトリを作成して build.gradle.kts 空のファイルを作成。
$ mkdir hello-serialization
$ cd hello-serialization
$ touch build.gradle.kts
build.gradle.kts を以下の内容にします。
plugins {
kotlin("js") version "1.7.22"
//kotlin("plugin.serialization") version "1.7.22"
id("org.jetbrains.kotlin.plugin.serialization") version "1.7.22"
}
version = "0.1"
repositories {
mavenCentral()
}
dependencies {
implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:1.4.1")
}
kotlin {
js(IR) {
browser {
webpackTask {
outputFileName = "hello_lib.js"
output.library = "helloLib"
}
}
nodejs()
binaries.library()
binaries.executable()
}
}
plugins での指定は、以下のどちらでも問題ないようです。
kotlin("plugin.serialization") version "1.7.22" id("org.jetbrains.kotlin.plugin.serialization") version "1.7.22"
id ではなく kotlin とすると org.jetbrains.kotlin がそれ(ここでは plugin.serialization)の前に足されるようです。 ドキュメント読んで確認したわけではなくエラーメッセージなどから推測しただけなので、その点はあしからず。
次に Main.kt を書きます。
$ mkdir -p src/main/kotlin
$ touch src/main/kotlin/Main.kt
Main.kt の内容は以下の通り。
import kotlinx.serialization.json.*
@ExperimentalJsExport
@JsExport
fun doJson(): String {
val jsonElement: JsonElement = Json.parseToJsonElement( """{"hello":"world"}""" )
val helloContent: String = jsonElement.jsonObject["hello"]?.jsonPrimitive?.contentOrNull?:""
return helloContent
}
doJson() すると serialization のコードを実行して文字列を返すだけです。
それでは js を生成して、index.js から使えるか試します。 まず、js を生成。(gradle バージョンも確認します。)
$ gradle -version
------------------------------------------------------------
Gradle 7.6
------------------------------------------------------------
Build time: 2022-11-25 13:35:10 UTC
Revision: daece9dbc5b79370cc8e4fd6fe4b2cd400e150a8
Kotlin: 1.7.10
Groovy: 3.0.13
Ant: Apache Ant(TM) version 1.10.11 compiled on July 10 2021
JVM: 17.0.5 (Private Build 17.0.5+8-Ubuntu-2ubuntu122.04)
OS: Linux 5.15.0-56-generic amd64
$ gradle build
必要なら gradle wrapper しておきましょう。
結果が build/distributions/ 以下に hello_lib.js, hello_lib.js.map が生成されます。 これを使う index.js を書きます。
const helloLib = require('./build/distributions/hello_lib');
const v = helloLib.doJson();
console.log(v);
実行(バージョンも確認します。)
$ node --version
v18.12.1
$ node index.js
world
できました。
Serialization ができるか試します。 (実際は deserialize しかしてませんが、まあそれはともかく。)
Main.kt を以下に変更。
import kotlinx.serialization.Serializable
import kotlinx.serialization.decodeFromString
@Serializable
data class Pokemon(val name: String)
@ExperimentalJsExport
@JsExport
fun doDeserialization(): String {
val pikachu: Pokemon = Json.decodeFromString<Pokemon>( """{"name":"Pikachu"}""" )
return pikachu.name
}
json 文字列から Pokemon クラスを生成しています。
これを js に変換します。
$ gradle build
index.js を doDeserialization() 関数を使うように変更。
const helloLib = require('./build/distributions/hello_lib');
const v = helloLib.doDeserialization();
console.log(v);
実行:
$ node index.js
pikachu
できました。
Kotlin Seriazation を使ったコードを Kotlin/JS でコンパイルして JS に変換して、Node.js から使えることがわかりました。 型を多用するなど JS より Kotlin の方が記述しやすい部分に使用できそう。