how to run compiled class file in Kotlin? - kotlin

Jetbrains provides some documentation but I can't find how to run compiled class file of Kotlin.
hello.kt:
fun main(args : Array<String>) {
println("Hello, world!")
}
compile:
$ kotlinc -out dist -src hello.kt
$ ls dist
namespace.class
$ java dist/namespace
Exception in thread "main" java.lang.NoClassDefFoundError: dist/namespace (wrong name: namespace)
$ java -jar /usr/local/kotlin/lib/kotlin-runtime.jar
Failed to load Main-Class manifest attribute from
/usr/local/kotlin/lib/kotlin-runtime.jar
How to run Kotlin program?

Knowing the Name of Your Main Class
Currently (Kotlin since M14 including up to 1.0 betas), to run a Kotlin class you are actually running a special class that is created at the file level that hold your main() and other functions that are top-level (outside of a class or interface). So if your code is:
// file App.kt
package com.my.stuff
public fun main(args: Array<String>) {
...
}
Then you can execute the program by running the com.my.stuff.AppKt class. This name is derived from your filename with Kt appended (previous versions appended KT but from later betas and 1.0 is Kt). You can change the name of this class within the file by adding this file-targeted annotation:
#file:JvmName("MyApp")
Or you can also put your main() into a class with a companion object and make it static using the JvmStatic annotation. Therefore your class name is the one you chose:
// file App.kt
package com.my.stuff
public class MyApp {
companion object {
#JvmStatic public fun main(args: Array<String>) {
...
}
}
}
Now for either of these methods, you just run the class com.my.stuff.MyApp
What other JAR files do I need?
You need your application JAR and any dependencies. For Kotlin specific JARs when outside of Maven/Gradle you need a Kotlin distribution which contains:
kotlin-runtime.jar (combined runtime and stdlib)
kotlin-reflect.jar only if using Kotlin reflection
kotlin-test.jar for unit tests that use Kotlin assertion classes
Within Maven/Gradle currently there is also a separate kotlin-stdlib.jar
Running from Intellij
If in Intellij (if it is your IDE) you can right click on the main() function and select Run, it will create a runtime configuration for you and show the fully qualified class name that will be used. You can always use that if you are unsure of the name of the generated class.
Running from Gradle
You can also use the Gradle Application plugin to run a process from Gradle, or to create a runnable system that includes a zip/tgz of your JAR and all of its dependencies, and a startup script. Using the example class above, you would add this to your build.gradle:
apply plugin: 'application'
mainClassName = 'com.my.stuff.AppKt'
// optional: add one string per argument you want as the default JVM args
applicationDefaultJvmArgs = ["-Xms512m", "-Xmx1g"]
And then from the command-line use:
// run the program
gradle run
// debug the program
gradle run --debug-jvm
// create a distribution (distTar, distZip, installDist, ...)
gradle distTar
Running Directly from Java Command-line
If you have a runnable JAR, and assuming KOTLIN_LIB points to a directory where Kotlin runtime library files reside:
java -cp $KOTLIN_LIB/kotlin-runtime.jar:MyApp.jar com.my.stuff.AppKt
See the notes above about other JAR files you might need. A slight variation if you have a runnable JAR (with the manifest pointing at com.my.stuff.AppKt as the main class):
java -cp $KOTLIN_LIB/kotlin-runtime.jar -jar MyApp.jar
Running using the Kotlin command-line tool
If you install Kotlin tools via Homebrew or other package manager. (on Mac OS X brew update ; brew install kotlin) Then it is very simple to run:
kotlin -cp MyApp.jar com.my.stuff.AppKt
This command adds the runtime to the classpath provided, then runs the class. You may need to add additional Kotlin libraries as mentioned in the section above "Running from Java."
Creating runnable JAR with the Kotlin compiler
This is not very common since most people use other build tools, but the Kotlin compiler can create a runnable Jar that solves this for you (see http://kotlinlang.org/docs/tutorials/command-line.html) when it bundles the runtime and your code together. Although this isn't as common when using tools such as Maven and Gradle, or IDE builds. Then run using the normal Java:
java -jar MyApp.jar

We ran into the same program and blogged our solution here: http://blog.ocheyedan.net/blog/2012/02/19/running-kotlin-code/
Basically you just need to invoke java with the -cp and the main class of 'namespace'. From your question, the java invocation would look something like this:
java -cp /usr/local/kotlin/lib/kotlin-runtime.jar:dist/namespace.class namespace

Update: In the newer versions of the Kotlin IDE plugin, you can use context Run-actions in the Editors pop-up menu.
If you are in the IDE, right-click the editor and choose "Run namespace"
Otherwise, compile and run the *.namespace class as a normal Java class.

I'm run jar which use kotlin like this
java -cp target/idea_test-1.0-SNAPSHOT.jar:lib/kotlin-runtime.jar testing.first seyfer
Hello seyfer
seed!

The docs give a nice and concise answer:
kotlinc hello.kt -include-runtime -d hello.jar
java -jar hello.jar
koclinc is located inside your IntelliJ IDEA directory
under IntelliJ\plugins\Kotlin\kotlinc\bin.
If you are running Windows use kotlinc-jvm.bat

Related

using kotlinx serialization inside a gradle plugin that creates a gradle task

I am trying to create a gradle plugin that will generate files (serialized from data classes) from a gradle task that can run in another project.
lets say that the classes that I am serializing are marked with some annotation #Annot and I find all the relevant classes with reflection in the gradle task (I made sure to depend on kotlin compile so that the binaries are created). The problem is that when I try to use
val clazz: Class<*>
clazz.kotlin.serializer()
I get a Serializer for class 'Type' is not found. (Type is the actual class that I found and is annotated with #Serializable and #Annot .
I am using gradle version 7.2, kotlin 1.5.21 (tried with 1.5.31 too)
The project that uses the plugin has a kotlinx serialization plugin enabled
What am I missing? why can’t I access the class serializer with the gradle task?
Note* if I run the above code in the target project (and not in the plugin then the serializer() function doesn't throw an exception
So This didn't work in a the way I wanted it to but I found a way to make it work.
I defined a task that extends JavaExec task:
tasks.create(createFilesTaskName, JavaExec::class.java) {
mainClass.set("package.of.file.SchemaKt")
classpath = sourceSets.getByName("main").runtimeClasspath
group = groupName
}
The code in SchemaKt is in the source set of my kotlin sources or alternatively in a package required by the current project.
The serializer() is accessible and working from there and I can run the schemas creation from a gradle task which is exactly what I needed.
I hope this helps someone in the future.

How do I apply a plugin in a .kts (Kotlin script) file?

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
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

Can I use kotlinx classes in Kotlin scripts?

Is it possible to import classes from kotlinx package in a simple Kotlin script?
myscript.kts:
import kotlinx.serialization.*
import kotlinx.serialization.json.*
println("")
Running the above script with kotlinc -script myscript.kts gives this error:
error: unresolved reference: kotlinx
When I checked kotlinc/lib/ directory, there exists kotlinx-coroutines-core.jar and so on.
I am using Kotlin compiler version 1.4.0.
You can execute kotlin like a simple bash script with dependencies if you change the name to *.main.kts
https://raw.githubusercontent.com/yschimke/okurl-scripts/master/commands/tube-status.main.kts
$ ./tube-status.main.kts
Good Service
Good Service
Minor Delays
Part Closure
Minor Delays
Good Service
Minor Delays
Good Service
Part Closure
Good Service
Planned Closure
First of, the imports you have are related to the kotlin serialization library not the coroutines one.
As for running your script you need to specify the dependencies to the compiler. You can run your script like this :
kotlinc -script myscript.kts -classpath kotlinx-serialization-runtime-0.20.0-1.4.0-rc-95.jar
I've used the old kotlin serialization runtime but you'll need to adapt the command to your needs.

How to include a jar file in kotlin script

I want to separate some generic code from my kotlin script file so that it can be reused.
I did this:
// MyLib.kt
package myLib
fun say_hello(name : String)
{
println("hello $name")
}
I compiled this file to create a jar file:
kotlinc myLib.kt -include-runtime -d myLib.jar
Then I created a script file:
// myScript.kts
import myLib.*
say_hello("Arvind")
But i can not compile the script file as it neither recognizes myLib package nor say_hello() function.
What is the correct way to do this.
Question Update:
I am using kscript to run my script. Typing a lot e.g.,
kotlin -cp myLib.jar myScript.kts
every time I have to run the script, thus defeats the motive of using kscript.
Is not there any way so that I need not give path of jar every time command line. Instead I want to use it in a kscript way, i.e.
./myScript
You need to include the myLib.jar in the classpath, for example:
kotlin -cp myLib.jar myScript.kts
Also, you do not need to compile myLib with -include-runtime, unless you want to create a self-contained and runnable jar (see example).
Update:
Rename myScript.kts to myScript.main.kts and change its content to:
#!/usr/bin/env kotlin
#file:DependsOn("myLib.jar")
import myLib.*
say_hello("Arvind")
You now can call it (don't forget to set execute permissions):
./myScript.main.kts
If instead of the myLib.jar file you want to include the myLib.kt script replace #file:DependsOn("myLib.jar") by #file:Import("myLib.kt").

Accessing libraries in IntelliJ GDSL script

I have a Groovy DSL script which uses classes from libraries, for example org.joda.time.LocalDateTime.
In the actual Groovy DSL script I don't have the import to the class, it's added later when executing the script.
I wrote a GDSL script for code completion in IntelliJ, but IntelliJ doesn't recognize LocalDateTime class in my script.
When I try to do an import to that class in the GDSL script, I get an error saying that the class cannot be resolved, even though it's on the project's classpath, cause when I run the project's tests for example, it works.
How can I make IntelliJ see classes from external libraries in my DSL script using GDSL script?