org.json で JSON 操作するコードを書いていたが Kotlin/JS ではこれは使えない。 そのかわりに Serialization JSON を使った。
以前のメモ
Serialization の場合、データクラスを JSON にしたり、逆にJSON から特定のデータクラスに戻したりといったことが簡単にできる。 でも結局変換コードかかないといけないんでしょ?と思ったら String とか List<String> などの型ならば、 特別なコードを書く必要はなく encode / decode できた。これはよい。
Gradle:
$ gradle --version
------------------------------------------------------------
Gradle 8.4
------------------------------------------------------------
Build time: 2023-10-04 20:52:13 UTC
Revision: e9251e572c9bd1d01e503a0dfdf43aedaeecdc3f
Kotlin: 1.9.10
Groovy: 3.0.17
Ant: Apache Ant(TM) version 1.10.13 compiled on January 4 2023
JVM: 17.0.12 (Ubuntu 17.0.12+7-Ubuntu-1ubuntu222.04)
OS: Linux 6.8.0-40-generic amd64
Node.js:
$ node --version
v20.17.0
$ mkdir hello
$ cd hello
$ touch build.gradle.kts
build.gradle.kts に次のように記述:
plugins {
kotlin("multiplatform") version "2.0.0"
kotlin("plugin.serialization") version "2.0.20"
}
version = "0.1"
repositories {
mavenCentral()
}
kotlin {
js {
nodejs()
binaries.library()
}
sourceSets {
jsMain.dependencies {
implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:1.7.2")
}
}
}
ポイントは plugins セクションにこれを記述し:
plugins {
...
kotlin("plugin.serialization") version "2.0.20"
}
jsMain の依存として kotlinx-serialization-json を指定します。
kotlin {
...
sourceSets {
jsMain.dependencies {
implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:1.7.2")
}
}
}
続いて Main.kt の用意:
$ mkdir -p src/jsMain/kotlin/
$ touch src/jsMain/kotlin/Main.kt
内容は次のようにします。
// Main.kt
import kotlinx.serialization.json.Json
import kotlinx.serialization.Serializable
import kotlinx.serialization.encodeToString
import kotlinx.serialization.decodeFromString
typealias JSON = String
@Serializable
data class Pokemon(val name: String)
@Serializable
data class Trainer(
val name: String,
val pokemons: List<Pokemon>)
@ExperimentalJsExport
@JsExport
fun buildTrainerJson(trainerName: String, vararg pokemonNames: String): JSON {
val pokemons = pokemonNames.map { Pokemon(it) }
val trainer = Trainer(trainerName, pokemons)
return Json.encodeToString( trainer )
}
@ExperimentalJsExport
@JsExport
fun getTrainerNameAndPokemonNames(json: JSON): String {
val trainer = Json.decodeFromString<Trainer>( json )
val trainerName = trainer.name
val pokemonNames = trainer.pokemons.map { it.name }.joinToString(", ")
return "$trainerName: ($pokemonNames)"
}
この部分、複数のポケモン名を渡す部分は vararg を使用しました。
fun buildTrainerJson(trainerName: String, vararg pokemonNames: String): JSON {
はじめ、 List<String> としてこのように記述していたのですが、意図通り作動しませんでした。
fun buildTrainerJson(trainerName: String, pokemonNames: List<String>): JSON {
$ gradle assemble
エラーがなければ gradle wrapper しておきます。
$ gradle wrapper
それでは build します。
$ ./gradlew build
これで build/js に Node.js のプロジェクトが生成されます。
build/js/index.js を次の内容で用意します。
const hello = require("hello")
const json = hello.buildTrainerJson("Satoshi", ["Pikachu", "Squirtle"])
console.log(json)
const value = hello.getTrainerNameAndPokemonNames(json)
console.log(value)
それでは実行してみます。
$ cd build/js
$ node index.js
{"name":"Satoshi","pokemons":[{"name":"Pikachu"},{"name":"Squirtle"}]}
Satoshi: (Pikachu, Squirtle)
うまくいきました。
$ npm install webpack@5.92.0 --save-dev
$ npm install webpack-cli@5.1.4 --save-dev
webpack.config.js を用意。
const path = require('path');
module.exports = {
mode: 'production',
entry: './packages/hello/kotlin/hello.js',
output: {
library: 'hello',
libraryTarget: 'commonjs',
//libraryTarget: 'this',
path: __dirname,
filename: 'hellolib.js'
}
}
詳細は割愛しますが、 libraryTarget に this を指定すると、ブラウザ上で直接実行する js として使えます。
$ npx webpack --config webpack.config.js
hellolib.js が成果物としてのライブラリです。
作動を確認します。
// main.js
const hellolib = require("./hellolib.js")
console.log(hellolib)
const json = hellolib.hello.buildTrainerJson("Satoshi", ["Pikachu", "Squirtle"])
console.log(json)
const value = hellolib.hello.getTrainerNameAndPokemonNames(json)
console.log(value)
実行。
$ node main.js
{
hello: {
buildTrainerJson: [Function: D],
getTrainerNameAndPokemonNames: [Function: O]
}
}
{"name":"Satoshi","pokemons":[{"name":"Pikachu"},{"name":"Squirtle"}]}
Satoshi: (Pikachu, Squirtle)
できました。
Kotlin/JS する場合、JavaScript 側とのやりとりで JSON を使うことが多いので、Serialization 便利です。