I've written a simple kotlin source file in order to get started, and a gradle script file.
But I can't figure out how to add the main func to the manifest, so that the jar could be self-executable.
Here my build.gradle script :
buildscript {
repositories {
mavenCentral()
}
dependencies {
classpath 'org.jetbrains.kotlin:kotlin-gradle-plugin:0.9.66'
}
}
apply plugin: "kotlin"
repositories {
mavenCentral()
}
dependencies {
compile 'org.jetbrains.kotlin:kotlin-stdlib:0.9.66'
}
jar {
manifest {
attributes 'Main-Class': 'com.loloof64.kotlin.exps.ExpsPackage'
}
}
Here is my com.loloof64.kotlin.exps.Multideclarations.kt
package com.loloof64.kotlin.exps
class Person(val firstName: String, val lastName: String) {
fun component1(): String {
return firstName
}
fun component2(): String {
return lastName
}
}
fun main(args: Array < String > ) {
val(first, last) = Person("Laurent", "Bernabé")
println("First name : $first - Last name : $last")
}
When I launch the jar from terminal (java -jar MYJar.jar) I get the following stacktrace, saying me that the kotlin reflection library classes are missing, and indeed they have not been added to the jar. It seems that I am missing the kotlin-compiler artifact classes from the final jar, and also the kotlin-stdlib sources, but I don't know how to adapt the gradle build.
$> java -jar build/libs/kotlin_exps.jar
Exception in thread "main" java.lang.NoClassDefFoundError: kotlin/reflect/jvm/internal/InternalPackage
at com.loloof64.kotlin.exps.ExpsPackage.<clinit>(MultiDeclarations.kt)
Caused by: java.lang.ClassNotFoundException: kotlin.reflect.jvm.internal.InternalPackage
at java.net.URLClassLoader$1.run(URLClassLoader.java:372)
at java.net.URLClassLoader$1.run(URLClassLoader.java:361)
at java.security.AccessController.doPrivileged(Native Method)
at java.net.URLClassLoader.findClass(URLClassLoader.java:360)
at java.lang.ClassLoader.loadClass(ClassLoader.java:424)
at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:308)
at java.lang.ClassLoader.loadClass(ClassLoader.java:357)
... 1 more
I am using Kotlin 0.9.66 and gradle 2.1
Add the plugin application
, then set the mainClassName
as
mainClassName = '[your_namespace].[your_arctifact]Kt'
For instance, suppose you have placed the following code in a file named main.kt
:
package net.mydomain.kotlinlearn
import kotlin
import java.util.ArrayList
fun main(args: Array<String>) {
println("Hello!")
}
your build.gradle
should be:
apply plugin: 'kotlin'
apply plugin: 'application'
mainClassName = "net.mydomain.kotlinlearn.MainKt"
In fact Kotlin is building a class to encapsulate your main function named with the same name of your file - with Title Case.
I've found the workaround (thanks to MkYong website)
- The gradle script needed the kotlin-compiler artifact as a dependency
- The gradle script needed a way to collect all kotlin files and put them into the jar.
So i get with the following gradle script :
buildscript {
repositories {
mavenCentral()
}
dependencies {
classpath 'org.jetbrains.kotlin:kotlin-gradle-plugin:1.0.1-2'
}
}
apply plugin: "kotlin"
repositories {
mavenCentral()
}
dependencies {
compile 'org.jetbrains.kotlin:kotlin-stdlib:1.0.1-2'
}
jar {
manifest {
attributes 'Main-Class': 'com.loloof64.kotlin.exps.MultideclarationsKT'
}
// NEW LINE HERE !!!
from { configurations.compile.collect { it.isDirectory() ? it : zipTree(it) } }
}
Thanks, for me it worked adding the jar section
jar {
manifest {
attributes 'Main-Class': 'com.photofiles.Application'
}
from { configurations.compile.collect { it.isDirectory() ? it : zipTree(it) } }
}
No need for the application plugin.
In case you happen to be dumb, like me:
Don't create your IntelliJ run configuration as an Application. IntelliJ will assume it's Java & it will never work. Instead, use the "Kotlin" entry.
If using Gradle
with the Kotlin
DSL
, then my duplicate question has an answer of:
import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
import com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar
plugins {
kotlin("jvm") version "1.2.51"
id("com.github.johnrengelman.shadow") version "2.0.4"
}
group = "xxx.yyy"
version = "1.0-SNAPSHOT"
repositories {
mavenCentral()
}
dependencies {
implementation(kotlin("stdlib-jdk8"))
}
tasks.withType<KotlinCompile> {
kotlinOptions.jvmTarget = "1.8"
}
tasks.withType<ShadowJar> {
manifest.attributes.apply {
put("Implementation-Title", "Gradle Jar File Example")
//put("Implementation-Version" version)
put("Main-Class", "HelloKotlinWorld.App")
}
Which is, I think, the simplest solution. Oh, perhaps you're using just Kotlin
itself and not the DSL
.