I am attempting to use kotlinx.serialization in a multiplatform (JVM/JS) project.
When I add @Serializable
annotation to some data classes in some class in common module:
@Serializable
data class User(
val user: String
)
The build succeeds without errors, but it doesn't look like the encoders/decoders are generated.
In build/generated-src
I don't see any related kotlin files which provide the encodeToString
extension function, and when I try to use something like:
JSON.encodeToString(User(login = "X"))
I get an Unresolved reference error:
Unresolved reference. None of the following candidates is applicable because of receiver type mismatch:
public inline fun <reified T> StringFormat.encodeToString(value: TypeVariable(T)): String defined in kotlinx.serialization
Any help to resolve this would be appreciated. Thanks in advance.
My build.gradle.kts:
import org.jetbrains.kotlin.gradle.targets.js.nodejs.NodeJsRootPlugin
import org.jetbrains.kotlin.gradle.targets.js.webpack.KotlinWebpack
import org.jetbrains.kotlin.gradle.targets.js.webpack.KotlinWebpackConfig
/* buildscript {
dependencies {
val kotlinVersion: String by System.getProperties()
classpath(kotlin("serialization", version = kotlinVersion))
}
} */
plugins {
val kotlinVersion: String by System.getProperties()
kotlin("multiplatform") version kotlinVersion
id("kotlinx-serialization") version kotlinVersion
val kvisionVersion: String by System.getProperties()
id("kvision") version kvisionVersion
}
version = "1.0.0-SNAPSHOT"
group = "tech.lorefnon"
repositories {
mavenCentral()
jcenter()
maven { url = uri("https://dl.bintray.com/kotlin/kotlin-eap") }
maven { url = uri("https://kotlin.bintray.com/kotlinx") }
maven { url = uri("https://dl.bintray.com/kotlin/kotlin-js-wrappers") }
maven { url = uri("https://dl.bintray.com/rjaros/kotlin") }
maven { url = uri("https://repo.spring.io/milestone") }
maven { url = uri("https://oss.sonatype.org/content/repositories/snapshots") }
mavenLocal()
}
// Versions
val kotlinVersion: String by System.getProperties()
val kvisionVersion: String by System.getProperties()
val ktorVersion: String by project
val logbackVersion: String by project
val commonsCodecVersion: String by project
val webDir = file("src/frontendMain/web")
val mainClassName = "io.ktor.server.netty.EngineMain"
kotlin {
jvm("backend") {
compilations.all {
kotlinOptions {
jvmTarget = "1.8"
freeCompilerArgs = listOf("-Xjsr305=strict")
}
}
}
js("frontend") {
browser {
runTask {
outputFileName = "main.bundle.js"
sourceMaps = false
devServer = KotlinWebpackConfig.DevServer(
open = false,
port = 3000,
proxy = mapOf(
"/kv/*" to "http://localhost:8080",
"/login" to "http://localhost:8080",
"/logout" to "http://localhost:8080",
"/kvws/*" to mapOf("target" to "ws://localhost:8080", "ws" to true)
),
contentBase = listOf("$buildDir/processedResources/frontend/main")
)
}
webpackTask {
outputFileName = "main.bundle.js"
}
testTask {
useKarma {
useChromeHeadless()
}
}
}
binaries.executable()
}
sourceSets {
val commonMain by getting {
dependencies {
implementation(kotlin("stdlib-common"))
api("pl.treksoft:kvision-server-ktor:$kvisionVersion")
implementation("org.jetbrains.kotlinx:kotlinx-collections-immutable:0.3.3")
implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:1.0.1")
}
kotlin.srcDir("build/generated-src/common")
kotlin.srcDir("src/commonMain/kotlin")
}
val commonTest by getting {
dependencies {
implementation(kotlin("test-common"))
implementation(kotlin("test-annotations-common"))
}
}
val backendMain by getting {
dependencies {
implementation(kotlin("stdlib-jdk8"))
implementation(kotlin("reflect"))
implementation("com.auth0:java-jwt:3.11.0")
implementation("io.ktor:ktor-server-netty:$ktorVersion")
implementation("io.ktor:ktor-auth:$ktorVersion")
implementation("io.ktor:ktor-auth-jwt:$ktorVersion")
implementation("ch.qos.logback:logback-classic:$logbackVersion")
implementation("commons-codec:commons-codec:$commonsCodecVersion")
implementation("org.redisson:redisson:3.14.0")
implementation("org.jetbrains.kotlinx:kotlinx-coroutines-jdk8:1.4.2")
}
}
val backendTest by getting {
dependencies {
implementation(kotlin("test"))
implementation(kotlin("test-junit"))
}
}
val frontendMain by getting {
resources.srcDir(webDir)
dependencies {
implementation("pl.treksoft:kvision:$kvisionVersion")
implementation("pl.treksoft:kvision-redux:${kvisionVersion}")
implementation("pl.treksoft:kvision-bootstrap:$kvisionVersion")
implementation("pl.treksoft:kvision-bootstrap-select:$kvisionVersion")
implementation("pl.treksoft:kvision-datacontainer:$kvisionVersion")
implementation("pl.treksoft:kvision-bootstrap-dialog:$kvisionVersion")
implementation("pl.treksoft:kvision-fontawesome:$kvisionVersion")
implementation("pl.treksoft:kvision-i18n:$kvisionVersion")
implementation(npm("redux-logger", "3.0.6"))
}
kotlin.srcDir("build/generated-src/frontend")
}
val frontendTest by getting {
dependencies {
implementation(kotlin("test-js"))
implementation("pl.treksoft:kvision-testutils:$kvisionVersion:tests")
}
}
}
}
fun getNodeJsBinaryExecutable(): String {
val nodeDir = NodeJsRootPlugin.apply(project).nodeJsSetupTaskProvider.get().destination
val isWindows = System.getProperty("os.name").toLowerCase().contains("windows")
val nodeBinDir = if (isWindows) nodeDir else nodeDir.resolve("bin")
val command = NodeJsRootPlugin.apply(project).nodeCommand
val finalCommand = if (isWindows && command == "node") "node.exe" else command
return nodeBinDir.resolve(finalCommand).absolutePath
}
afterEvaluate {
tasks {
getByName("frontendProcessResources", Copy::class) {
dependsOn("compileKotlinFrontend")
exclude("**/*.pot")
doLast("Convert PO to JSON") {
destinationDir.walkTopDown().filter {
it.isFile && it.extension == "po"
}.forEach {
exec {
executable = getNodeJsBinaryExecutable()
args(
"$buildDir/js/node_modules/gettext.js/bin/po2json",
it.absolutePath,
"${it.parent}/${it.nameWithoutExtension}.json"
)
println("Converted ${it.name} to ${it.nameWithoutExtension}.json")
}
it.delete()
}
}
}
create("frontendArchive", Jar::class).apply {
dependsOn("frontendBrowserProductionWebpack")
group = "package"
archiveAppendix.set("frontend")
val distribution =
project.tasks.getByName("frontendBrowserProductionWebpack", KotlinWebpack::class).destinationDirectory!!
from(distribution) {
include("*.*")
}
from(webDir)
duplicatesStrategy = DuplicatesStrategy.EXCLUDE
into("/assets")
inputs.files(distribution, webDir)
outputs.file(archiveFile)
manifest {
attributes(
mapOf(
"Implementation-Title" to rootProject.name,
"Implementation-Group" to rootProject.group,
"Implementation-Version" to rootProject.version,
"Timestamp" to System.currentTimeMillis()
)
)
}
}
getByName("backendProcessResources", Copy::class) {
duplicatesStrategy = DuplicatesStrategy.EXCLUDE
}
getByName("backendJar").group = "package"
create("jar", Jar::class).apply {
dependsOn("frontendArchive", "backendJar")
group = "package"
manifest {
attributes(
mapOf(
"Implementation-Title" to rootProject.name,
"Implementation-Group" to rootProject.group,
"Implementation-Version" to rootProject.version,
"Timestamp" to System.currentTimeMillis(),
"Main-Class" to mainClassName
)
)
}
val dependencies = configurations["backendRuntimeClasspath"].filter { it.name.endsWith(".jar") } +
project.tasks["backendJar"].outputs.files +
project.tasks["frontendArchive"].outputs.files
dependencies.forEach {
if (it.isDirectory) from(it) else from(zipTree(it))
}
exclude("META-INF/*.RSA", "META-INF/*.SF", "META-INF/*.DSA")
inputs.files(dependencies)
outputs.file(archiveFile)
duplicatesStrategy = DuplicatesStrategy.EXCLUDE
}
create("backendRun", JavaExec::class) {
dependsOn("compileKotlinBackend")
group = "run"
main = mainClassName
classpath =
configurations["backendRuntimeClasspath"] + project.tasks["compileKotlinBackend"].outputs.files +
project.tasks["backendProcessResources"].outputs.files
workingDir = buildDir
}
getByName("compileKotlinBackend") {
dependsOn("compileKotlinMetadata")
}
getByName("compileKotlinFrontend") {
dependsOn("compileKotlinMetadata")
}
}
}
And gradle.properties:
javaVersion=1.8
#Plugins
systemProp.kotlinVersion=1.4.20
systemProp.serializationVersion=1.0.1
#Dependencies
systemProp.kvisionVersion=3.17.2
ktorVersion=1.4.3
commonsCodecVersion=1.10
logbackVersion=1.2.3
kotlin.mpp.stability.nowarn=true
kotlin.js.compiler=legacy
org.gradle.jvmargs=-Xmx2g
And settings.gradle.kts:
pluginManagement {
repositories {
mavenCentral()
jcenter()
maven { url = uri("https://plugins.gradle.org/m2/") }
maven { url = uri("https://dl.bintray.com/kotlin/kotlin-eap") }
maven { url = uri("https://kotlin.bintray.com/kotlinx") }
maven { url = uri("https://dl.bintray.com/rjaros/kotlin") }
mavenLocal()
}
resolutionStrategy {
eachPlugin {
when {
requested.id.id == "kotlinx-serialization" -> useModule("org.jetbrains.kotlin:kotlin-serialization:${requested.version}")
requested.id.id == "kvision" -> useModule("pl.treksoft:kvision-gradle-plugin:${requested.version}")
}
}
}
}
rootProject.name = "test"