IntelliJ Show an Error on kotlinx.serialization, but compiling works - kotlin

I have a problem where IntelliJ tells me that the #Serializable annotation cannot be accessed as it's internal to kotlin.io etc. The kotlinx.serialization package also shows as an unresolved reference.
Apparently, this has something to do with using Kotlin 1.7.x as when I downgrade to Kotlin 1.6.10 the issue no longer presents itself. However, Gradle compiles and runs the application without issue even on 1.7.10. Therefore, this seems like ultimately an issue with IntelliJ and/or one of my settings.
This is a Kotlin Multiplatform project. I've tried many things to fix this:
Reloading Gradle Project
Refreshing Gradle Dependencies
Completely refreshing all project indexes via the new Repair IDE tool
Deleting .idea and .gradle folders
Adjusting the project structure versions
Generally messing around with versions and settings
My build.gradle.kts:
plugins {
application
kotlin("multiplatform") version Versions.kotlin
kotlin("plugin.serialization") version Versions.kotlin
}
group = "com.example"
version = "4.0"
repositories {
mavenCentral()
}
kotlin {
jvm {
compilations.all {
kotlinOptions.jvmTarget = "17"
}
withJava()
testRuns["test"].executionTask.configure {
useJUnitPlatform()
}
}
js {
binaries.executable()
browser {
commonWebpackConfig {
cssSupport.enabled = true
}
webpackTask {
outputFileName = "app.js"
}
}
}
sourceSets {
val commonMain by getting {
dependencies {
implementation("io.ktor:ktor-client-core:${Versions.ktor}")
implementation("io.ktor:ktor-client-websockets:${Versions.ktor}")
implementation("io.ktor:ktor-serialization-kotlinx-json:${Versions.ktor}")
implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:${Versions.serialization}")
}
}
val commonTest by getting {
dependencies {
implementation(kotlin("test-common"))
implementation(kotlin("test-annotations-common"))
}
}
val jvmMain by getting {
dependencies {
implementation("io.ktor:ktor-server-core:${Versions.ktor}")
implementation("io.ktor:ktor-server-auth:${Versions.ktor}")
implementation("io.ktor:ktor-serialization:${Versions.ktor}")
implementation("io.ktor:ktor-server-html-builder:${Versions.ktor}")
implementation("io.ktor:ktor-client-cio:${Versions.ktor}")
implementation("io.ktor:ktor-server-cio:${Versions.ktor}")
implementation("io.ktor:ktor-server-websockets:${Versions.ktor}")
}
}
val jvmTest by getting
val jsMain by getting {
dependencies {
implementation("io.ktor:ktor-client-js:${Versions.ktor}")
implementation("io.ktor:ktor-client-json:${Versions.ktor}")
implementation("io.ktor:ktor-client-auth:${Versions.ktor}")
implementation("io.ktor:ktor-client-websockets:${Versions.ktor}")
implementation("io.ktor:ktor-client-serialization:${Versions.ktor}")
implementation("org.jetbrains.kotlin-wrappers:kotlin-react:${Versions.react}")
implementation("org.jetbrains.kotlin-wrappers:kotlin-react-dom:${Versions.react}")
}
}
val jsTest by getting
}
}
application {
mainClass.set("com.example.app.ServerKt")
}
tasks.named<Copy>("jvmProcessResources") {
val jsBrowserDistribution = tasks.named("jsBrowserDistribution")
from(jsBrowserDistribution)
}
tasks.named<JavaExec>("run") {
dependsOn(tasks.named<Jar>("jvmJar"))
classpath(tasks.named<Jar>("jvmJar"))
}
object Versions {
const val ktor = "2.0.3"
const val kotlin = "1.7.10"
const val coroutines = "1.6.3"
const val serialization = "1.3.3"
const val react = "18.2.0-pre.358-compat"
}
The class that is having issues is:
import kotlinx.serialization.Serializable
#Serializable
data class Customer(val id: Int, val firstName: String, val lastName: String)
I appreciate any help I can get

Related

KSP on Kotlin Multiplatform fails on the kspJs with "Collection has more than one element."

I'm experimenting with KSP (Kotlin Symbol Processing) to see what it's capable of and I'm trying to get it working on a Kotlin Multiplatform project.
When I only enable kspJvm, it works perfectly, as soon as I enable kspJs as well, it fails with "Collection has more than one element."
I've recreated the issue in this demo github project:
https://github.com/janvladimirmostert/observable-demo
In my processor, I have the following config:
build.gradle.kts:
val kspVersion: String by project
group = "io.jvaas"
plugins {
kotlin("multiplatform")
}
kotlin {
jvm {
compilations.all {
kotlinOptions.jvmTarget = "11"
}
}
sourceSets {
val commonMain by getting
val jvmMain by getting {
dependencies {
implementation("com.google.devtools.ksp:symbol-processing-api:$kspVersion")
}
}
}
}
gradle.properties:
kotlinVersion=1.6.0
kspVersion=1.6.0-1.0.1
src/commonMain/kotlin/io/jvaas/observe/Observable.kt
package io.jvaas.observe
annotation class Observable
src/jvmMain/resources/META-INF/services/com.google.devtools.ksp.processing.SymbolProcessorProvider
io.jvaas.observe.ObservableProcessorProvider
src/jvmMain/kotlin/io/jvaas/observe/ObservableProcessor.kt
class ObservableProcessor(
val codeGenerator: CodeGenerator,
val logger: KSPLogger,
) : SymbolProcessor {
...
}
class ObservableProcessorProvider : SymbolProcessorProvider {
override fun create(
environment: SymbolProcessorEnvironment
): SymbolProcessor {
return ObservableProcessor(environment.codeGenerator, environment.logger)
}
}
In my consumer I have the following:
import org.jetbrains.kotlin.gradle.targets.js.webpack.KotlinWebpackOutput.Target.UMD
group = "com.od"
plugins {
application
id("com.google.devtools.ksp") version "1.6.0-1.0.1"
kotlin("plugin.serialization")
kotlin("multiplatform")
id("com.github.johnrengelman.shadow")
}
kotlin {
jvm {
compilations.all {
kotlinOptions.jvmTarget = "11"
}
}
js(IR) {
browser {
binaries.executable()
webpackTask {
output.libraryTarget = UMD
}
}
}
sourceSets {
val commonMain by getting {
dependencies {
val serializationVersion = "1.3.1"
implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:$serializationVersion")
implementation("io.jvaas:jvaas-observe")
}
}
val commonTest by getting
val jvmMain by getting {
dependencies {
}
}
val jvmTest by getting {
dependencies {
implementation(kotlin("test-junit"))
}
}
val jsMain by getting
val jsTest by getting {
dependencies {
implementation(kotlin("test-js"))
}
}
}
}
dependencies {
add("kspJvm", "io.jvaas:jvaas-observe")
// add("kspJs", "io.jvaas:jvaas-observe") // <--- fails if enabled
//ksp("io.jvaas:jvaas-observe")
}
application {
mainClassName = "com.od.demo.Main"
}
applications/od-server/src/commonMain/kotlin/com/od/demo/Blah.kt
package com.od.demo
import io.jvaas.observe.Observable
#Observable
class Blah {
var test1: String = ""
var test2: Int = 0
var test3: Array<String> = arrayOf()
}
This correctly gets processed when the kspJvm option is enabled and correctly outpus a file at
applications/od-server/build/generated/ksp/jvmMain/kotlin/com/od/demo/BlahO.kt
If I enable it for kspJs, it fails
add("kspJs", "io.jvaas:jvaas-observe")
Execution failed for task ':applications:od-server:compileProductionExecutableKotlinJs'.
> Failed to calculate the value of task ':applications:od-server:compileProductionExecutableKotlinJs' property 'entryModule$kotlin_gradle_plugin'.
> Collection has more than one element.
I've tried the usual gradle build --info / --debug / --scan but it's not clear where I can start looking to resolve this issue.
As mentioned above, I made a demo project to demonstrate the error:
https://github.com/janvladimirmostert/observable-demo
Any ideas on how to resolve that error?
Issue has been fixed in https://github.com/google/ksp/issues/744 but I'm not sure if it has been released yet.

Imports not resolving in generated GraphQL queries with Apollo3

I've noticed that when I generate class files from GraphQL queries, the imports for Apollo3 aren't resolving. See the screenshot below.
I'm using the Apollo3 GraphQL library in a Kotlin Multiplatform project. The Apollo Get Started With Multiplatform docs are pretty confusing and I may have my project configured incorrectly.
I can download the schema, and generate the files without a problem.
./build.gradle.kts
buildscript {
repositories {
gradlePluginPortal()
google()
mavenCentral()
}
dependencies {
classpath("org.jetbrains.kotlin:kotlin-gradle-plugin:1.5.21")
classpath("com.android.tools.build:gradle:7.0.0")
}
}
allprojects {
repositories {
google()
mavenCentral()
}
}
tasks.register("clean", Delete::class) {
delete(rootProject.buildDir)
}
./shared/build.gradle.kts
import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinNativeTarget
plugins {
kotlin("multiplatform")
id("com.android.library")
id("com.apollographql.apollo3").version("3.0.0-alpha03")
}
kotlin {
android()
val iosTarget: (String, KotlinNativeTarget.() -> Unit) -> KotlinNativeTarget =
if (System.getenv("SDK_NAME")?.startsWith("iphoneos") == true)
::iosArm64
else
::iosX64
iosTarget("ios") {
binaries {
framework {
baseName = "shared"
}
}
}
sourceSets {
val commonMain by getting {
dependencies {
implementation("com.apollographql.apollo:apollo-runtime-kotlin:2.5.7")
}
}
val commonTest by getting {
dependencies {
implementation(kotlin("test-common"))
implementation(kotlin("test-annotations-common"))
}
}
val androidMain by getting
val androidTest by getting {
dependencies {
implementation(kotlin("test-junit"))
implementation("junit:junit:4.13.2")
}
}
val iosMain by getting
val iosTest by getting
}
}
android {
compileSdkVersion(30)
sourceSets["main"].manifest.srcFile("src/androidMain/AndroidManifest.xml")
defaultConfig {
minSdkVersion(23)
targetSdkVersion(30)
}
}
I was having the same issue. In my case, it was fixed by making sure the runtime dep is using the same version as the apollo plugin applied (3.0.0-alpha03).
So try changing the content in ./shared/build.gradle.kts file, replacing this line
implementation("com.apollographql.apollo:apollo-runtime-kotlin:2.5.7")
with
implementation("com.apollographql.apollo:apollo-runtime-kotlin:3.0.0-alpha03")

How to share kotlin multiplatform targets between submodules?

After an eternity I managed to setup a kotlin multi-platform and multi-module project. As there is almost no proper guide or documentation, I have just one more issue I couldn't solve.
Can I share kotlin multiplatform targets between the submodules?
Right now every submodule has a build.gradle.kts containing:
kotlin {
jvm {
compilations.all {
kotlinOptions.jvmTarget = "15"
}
}
js(IR) {
nodejs()
browser {
testTask {
useKarma {
useChromeHeadless()
webpackConfig.cssSupport.enabled = true
}
}
}
}
}
Obviously, I want all modules to compile to the same platforms using the same versions and it would be nice to not copy this snippet for every module.
Not to mention that the test dependencies are identical as well.
sourceSets {
val commonTest by getting {
dependencies {
implementation("io.kotest:kotest-framework-api:$kotestVersion")
implementation("io.kotest:kotest-assertions-core:$kotestVersion")
implementation("io.kotest:kotest-property:$kotestVersion")
}
}
val jvmTest by getting {
dependsOn(commonTest)
dependencies {
implementation("io.kotest:kotest-runner-junit5:$kotestVersion")
}
}
val jsTest by getting {
dependsOn(commonTest)
dependencies {
implementation("io.kotest:kotest-framework-engine:$kotestVersion")
}
}
}

Cannot import dependecies in kotlin multiplatform mobile

I created a new kotlin multiplatform mobile project. I followed official documentation.
Basic project is working, I was able to build it on android without problems.
I wanted to add some api and I found ktor, which I have never used before. I followed docs here: https://kotlinlang.org/docs/mobile/use-ktor-for-networking.html and tutorial here: https://proandroiddev.com/kotlin-multiplatform-very-beginners-guide-part-2-api-d54f7326dc57 and all changes I did are:
I added ktor libraries into build.gradle.kts(:shared):
sourceSets {
val commonMain by getting {
dependencies {
implementation ("io.ktor:ktor-client-core:1.5.0")
}
}
val commonTest by getting {
dependencies {
implementation(kotlin("test-common"))
implementation(kotlin("test-annotations-common"))
}
}
val androidMain by getting {
dependencies {
implementation("com.google.android.material:material:1.2.1")
implementation("io.ktor:ktor-client-android:1.5.0")
}
}
val androidTest by getting {
dependencies {
implementation(kotlin("test-junit"))
implementation("junit:junit:4.13")
}
}
val iosMain by getting {
dependencies {
implementation("io.ktor:ktor-client-ios:1.5.0")
}
}
val iosTest by getting
}
And I created Api class where I wanted to create and use the HttpClient:
class Api() {
private val client = HttpClient()
suspend fun fetch(): String {
return ""
}
}
BUT HttpCLient() is "Unresolved reference" and it cannot be imported. I also tried to manually add import io.ktor.client.HttpClient
but io is "Unresolved reference".
Also I tried numerous rebuilds/cleans/syncs.
What am I doing wrong? Am I missing something?
I encountered the same problem on windows 7 with Android Studio 4.1.3. It was solved when in the build script of the project, in the dependencies section of the buildscript, it was updated the version of the kotlin-gradle-plugin artifact from 1.4.10 to 1.4.32. Below is a copy paste from project build.gradle.kts:
buildscript {
repositories {
gradlePluginPortal()
jcenter()
google()
mavenCentral()
}
dependencies {
classpath("org.jetbrains.kotlin:kotlin-gradle-plugin:1.4.32")
classpath("com.android.tools.build:gradle:4.1.3")
}
}

Getting kotlinx serialization working in multiplatform project

I'm taking Kotlin seriazliation for a test drive in a multiplatform project in Kotlin 1.4-M2, following the tutorial on github, but i'm not getting the serialization bit to compile.
This is my build.gradle.kts
plugins {
val kotlinVersion = "1.4-M2"
kotlin("multiplatform") version kotlinVersion
kotlin("plugin.serialization") version kotlinVersion
}
repositories {
mavenCentral()
maven {
url = uri("https://dl.bintray.com/kotlin/kotlin-eap")
}
maven {
url = uri("https://kotlin.bintray.com/kotlinx")
}
jcenter()
gradlePluginPortal()
}
kotlin {
jvm {
compilations.all {
kotlinOptions.jvmTarget = "11"
}
}
js(IR) {
moduleName = "hotel"
browser {
dceTask {
keep(
...
)
}
binaries.executable()
}
}
sourceSets {
// val serializationVersion = "0.20.0-1.4-M2"
val serializationVersion = "0.20.0"
val commonMain by getting {
dependencies {
implementation(kotlin("stdlib-common"))
implementation("org.jetbrains.kotlinx:kotlinx-serialization-runtime-common:$serializationVersion")
}
}
val commonTest by getting {
dependencies {
implementation(kotlin("test-common"))
implementation(kotlin("test-annotations-common"))
}
}
val jvmMain by getting {
dependencies {
implementation(kotlin("stdlib-jdk8"))
implementation(kotlin("reflect"))
implementation("org.jetbrains.kotlinx:kotlinx-serialization-runtime:$serializationVersion")
}
}
val jvmTest by getting {
dependencies {
implementation(kotlin("test-junit"))
}
}
val jsMain by getting {
dependencies {
implementation(kotlin("stdlib-js"))
implementation("org.jetbrains.kotlinx:kotlinx-serialization-runtime-js:$serializationVersion")
}
}
val jsTest by getting {
dependencies {
implementation(kotlin("test-js"))
}
}
all {
languageSettings.enableLanguageFeature("InlineClasses")
}
}
}
I've tried it on a simple data class
#Serializable
data class Test(
val blah: Int = 0
)
import kotlinx.serialization.json.Json <<<--- Unresolved reference: kotlinx
import kotlinx.serialization.json.JsonConfiguration <<<--- Unresolved reference: kotlinx
import kotlin.js.ExperimentalJsExport
import kotlin.js.JsExport
...
fun main() {
val json = Json(JsonConfiguration.Default)
val jstring = json.toJson(Test.serializer(), Test(blah = 3))
println(jstring.toString())
}
It's complaining about Unresolved reference: kotlinx
Is there something specific one needs to do to make kotlinx imports work or should i be using different versions of the serializer libraries?
I got some help on Slack, thanks Sergey!
https://kotlinlang.org/eap/ shows the versions compatible with the EAP
or Milestone releases. You should use the serialization runtime
version 0.20.0-1.4-M2. Note that with this version, you need to add a
single dependency on kotlinx-serialization-runtime in the commonMain
source set, not separate dependencies on
kotlinx-serialization-runtime-common and the platform parts. See the
Specifying dependencies only once section here:
https://blog.jetbrains.com/kotlin/2020/06/kotlin-1-4-m2-released
So in short, my plugin should be matching my Kotlin version
plugins {
val kotlinVersion = "1.4-M2"
kotlin("multiplatform") version kotlinVersion
kotlin("plugin.serialization") version kotlinVersion
}
then under sourceSets, i should be using a single dependency instead of one per platform
sourceSets {
val serializationVersion = "0.20.0-1.4-M2"
val commonMain by getting {
dependencies {
implementation(kotlin("stdlib-common"))
implementation("org.jetbrains.kotlinx:kotlinx-serialization-runtime:$serializationVersion")
}
}
JVM and JS Main should not have any serialization plugin, so those lines should be removed
val jvmMain by getting {
dependencies {
implementation(kotlin("stdlib-jdk8"))
implementation(kotlin("reflect"))
// implementation("org.jetbrains.kotlinx:kotlinx-serialization-runtime:$serializationVersion") <<-- remove this
val jsMain by getting {
dependencies {
implementation(kotlin("stdlib-js"))
// implementation("org.jetbrains.kotlinx:kotlinx-serialization-runtime-js:$serializationVersion") <<-- remove this
}
}