5

Kotlin script (.main.kts) files have the idea of providing executable Kotlin code in ONE single standalone file, which is immensely convenient for scripting or when sharing code snippets on StackOverflow for example. In contrast to that, currently almost all Java/Kotlin uses a build system (e.g. gradle) with cryptic build files and a deep folder structure.

While I like the Kotlin script idea a lot, it seems to be barely used, with only 22 questions on StackOverflow and extremely sparse documentation and precious few Google results. I am able to pull in dependencies using @file:DependsOn inside of the actual script rather than the traditional build file:

build.gradle:

dependencies {
    implementation 'org.jetbrains.kotlinx:kotlinx-serialization-json:1.2.0'
}

foo.main.kts:

@file:DependsOn("org.jetbrains.kotlinx:kotlinx-serialization-json:1.2.0")

However, I can't find a way to use "apply plugin" in my .main.kts file. It's not used in any of the code snippets I found online.

build.gradle:

apply plugin: 'kotlinx-serialization'

foo.main.kts:

???

For reference, I attached an MWE below. The error message says the class Node is not serializable, but as pointed out in this question that message is misleading and the actual issue that apply plugin is missing, which I do not know how to use outside of a build.gradle file:

@file:DependsOn("org.jetbrains.kotlinx:kotlinx-serialization-json:1.2.0")

import kotlinx.serialization.decodeFromString
import kotlinx.serialization.Serializable
import kotlinx.serialization.json.Json

@Serializable
data class Node (val numbers: List<Int>)

val h = Json.decodeFromString<Node>(""" {"numbers": [1, 2, 3]} """)

Run it on Ubuntu:

snap install kotlin
kotlin foo.main.kts
xjcl
  • 12,848
  • 6
  • 67
  • 89

1 Answers1

5

kotlinx-serialization is a Gradle plugin, which adds to pipeline same-named compiler plugin - it generates the serializer() method for classes annotated with @Serializable.

When you compile Kotlin code with kotlinc compiler, you can attach the plugin by providing the path to its JAR file (it's bundled with the compiler) using the -Xplugin=/snap/kotlin/current/lib/kotlinx-serialization-compiler-plugin.jar compiler option.

For .kts files, there is a @file:CompilerOptions annotation, but currently (in Kotlin 1.5.10) this particular key is not supported (warning: the following compiler arguments are ignored on script compilation: -Xplugin)

Command line

On the command line you may use

kotlinc -script -Xplugin="/snap/kotlin/current/lib/kotlinx-serialization-compiler-plugin.jar" foo.main.kts

Script header

As a workaround you may use this shebang:

#!/usr/bin/env -S kotlinc -script -Xplugin="/snap/kotlin/current/lib/kotlinx-serialization-compiler-plugin.jar"

To run your script you need to turn it into an executable:

chmod u+x foo.main.kts

Now it could be run with:

./foo.main.kts
xjcl
  • 12,848
  • 6
  • 67
  • 89
  • 1
    Vote for this feature: https://youtrack.jetbrains.com/issue/KT-47384 – Михаил Нафталь Jul 01 '21 at 09:16
  • Great answer! I have version 2.28 of env/coreutils but the `-S` option is only on 2.30 or better. But just calling the script with `kotlinc` and the `-Xplugin` option works! – xjcl Jul 01 '21 at 09:53
  • Take a look at [kscript](https://github.com/holgerbrandl/kscript) project - it allows to pass compiler options with `//COMPILER_OPTS` (highly likely `-Xplugin` is supported) and provides more feature-rich support for kotlin scripting – Михаил Нафталь Jul 01 '21 at 09:58