Kotlin: How to create a runnable jar? - kotlin

I'm trying to create a runnable jar with Kotlin.
My gradle.build is this:
plugins {
id 'org.jetbrains.kotlin.jvm' version '1.3.11'
}
group 'com.github.dynamik'
version '1.0-SNAPSHOT'
apply plugin: 'application'
apply plugin: 'kotlin'
mainClassName = "interpreter.Repl"
repositories {
mavenCentral()
maven { setUrl("https://dl.bintray.com/hotkeytlt/maven") }
}
configurations {
ktlint
}
dependencies {
compile "org.jetbrains.kotlin:kotlin-stdlib-jdk8"
compile 'com.github.h0tk3y.betterParse:better-parse-jvm:0.4.0-alpha-3'
// https://mvnrepository.com/artifact/junit/junit
testCompile group: 'junit', name: 'junit', version: '4.4'
ktlint "com.github.shyiko:ktlint:0.31.0"
implementation 'com.github.ajalt:clikt:1.7.0'
implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-core:1.2.0'
}
compileKotlin {
kotlinOptions.jvmTarget = "1.8"
}
compileTestKotlin {
kotlinOptions.jvmTarget = "1.8"
}
run {
standardInput = System.in
}
jar {
manifest {
attributes 'Main-Class': 'interpreter.Repl'
}
}
(As it stands, when I do ./gradlew run, everything works as expected.)
I'm reading an article here on how to proceed, and it says to do: java -jar <MY_PROJECT_NAME>.jar.
I don't quite understand this -- where do we run this? I tried running it from my project root and I got an error:
Error: Unable to access jarfile <my_jarname>.jar

As of Gradle 5.4.1, a build.gradle.kts would need a section like this:
tasks.register<Jar>("uberJar") {
archiveClassifier.set("uber")
manifest {
attributes(
"Main-Class" to "mytest.AppKt",
"Implementation-Title" to "Gradle",
"Implementation-Version" to archiveVersion
)
}
from(sourceSets.main.get().output)
dependsOn(configurations.runtimeClasspath)
from({
configurations.runtimeClasspath.get().filter { it.name.endsWith("jar") }.map { zipTree(it) }
})
}

Ok, I figured it out :)
So, the way to create a jar is to go: ./gradlew build. This creates a jar in build/libs.
The problem is, when running that jar, one would run into an exception about java.lang.intrinsics because the kotlin stdlib hasn't been packed into the jar.
While there is a way to manually accomplish that, I found the easiest solution is to simply use the shadowjar plugin.
My build.gradle ended up looking like this:
buildscript {
repositories {
jcenter()
}
dependencies {
classpath 'com.github.jengelman.gradle.plugins:shadow:2.0.4'
}
}
plugins {
id 'org.jetbrains.kotlin.jvm' version '1.3.11'
}
group 'com.github.dynamik'
version '1.0-SNAPSHOT'
apply plugin: 'application'
apply plugin: 'kotlin'
apply plugin: 'java'
mainClassName = "interpreter.Repl"
repositories {
mavenCentral()
jcenter()
maven { setUrl("https://dl.bintray.com/hotkeytlt/maven") }
maven {
url = uri("https://plugins.gradle.org/m2/")
}
}
configurations {
ktlint
}
dependencies {
compile "org.jetbrains.kotlin:kotlin-stdlib-jdk8"
compile 'com.github.h0tk3y.betterParse:better-parse-jvm:0.4.0-alpha-3'
// https://mvnrepository.com/artifact/junit/junit
testCompile group: 'junit', name: 'junit', version: '4.4'
ktlint "com.github.shyiko:ktlint:0.31.0"
implementation 'com.github.ajalt:clikt:1.7.0'
implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-core:1.2.0'
}
apply plugin: 'com.github.johnrengelman.shadow'
compileKotlin {
kotlinOptions.jvmTarget = "1.8"
}
compileTestKotlin {
kotlinOptions.jvmTarget = "1.8"
}
run {
standardInput = System.in
}
jar {
manifest {
attributes 'Main-Class': 'interpreter.Repl'
}
}

When using a Kotlin main class you need to add a Kt at the end of the class name while referencing it on MANIFEST.
So, if your main class is called interpreter.Repl, use:
jar {
manifest {
attributes 'Main-Class': 'interpreter.ReplKt'
}
}
instead of
jar {
manifest {
attributes 'Main-Class': 'interpreter.Repl'
}
}

Related

How to fix `Expression 'jar' cannot be invoked as a function` error in gradle file?

I have the following gradle file. I'm getting a Expression 'jar' cannot be invoked as a function error on the line where jar is used (jar {). How can I fix this?
import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
plugins {
kotlin("jvm") version "1.6.21"
java
application
}
group = "me.talha"
version = "1.0-SNAPSHOT"
repositories {
mavenCentral()
}
dependencies {
testImplementation(kotlin("test"))
}
tasks.test {
useJUnitPlatform()
}
tasks.withType<KotlinCompile>() {
kotlinOptions.jvmTarget = "11"
}
application {
mainClass.set("MainKt")
}
jar {
manifest {
attributes 'Main-Class': 'MainKt'
}
}
Turns out I did not need to add any of the jar stuff. I can simply use the gradle distZip task which generates the needed jars and executable scripts and all works fine.

Gradle only compiles one file?

So I'm having troubles compiling multiple Gradle files. I'm new to Gradle so that's probably the first reason why it doesn't work as I intend.
Currently my Gradle file looks like this:
plugins {
id 'java'
id 'org.jetbrains.kotlin.jvm' version '1.3.61'
}
group 'com.github.polyrocketmatt.sierra'
version '1.0-SNAPSHOT'
sourceCompatibility = 1.8
targetCompatibility = 1.8
repositories {
mavenCentral()
maven {
url = "https://hub.spigotmc.org/nexus/content/repositories/snapshots"
}
maven {
url = "https://raw.github.com/PolyRocketMatt/PolyCommand/mvn-repo/"
}
maven {
url = "https://repo.minebench.de/"
}
}
dependencies {
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8"
testCompile group: 'junit', name: 'junit', version: '4.12'
compileOnly 'org.spigotmc:spigot-api:1.16.1-R0.1-SNAPSHOT'
compile 'org.jetbrains:annotations:16.0.1'
compile 'org.jetbrains.kotlinx:kotlinx-coroutines-core:1.4.2'
compile 'com.github.polyrocketmatt.polycommand:PolyCommand:1.1'
compile 'de.themoep:inventorygui:1.4.3-SNAPSHOT'
}
compileKotlin {
kotlinOptions.jvmTarget = "1.8"
}
compileTestKotlin {
kotlinOptions.jvmTarget = "1.8"
}
And my source tree looks like this:
It only compiles the Sierra class, and I want to compile with it all the other classes too of course. This is what I see when I decompile the JAR file Gradle builds for me:
How do I make sure all the other classes are compiled with it?

Swagger with Spring webflux dependency building issue

I work with kotlin gradle project. When i try to integrate swagger, it shows
Could not resolve io.springfox:springfox-swagger2:3.0.0-SNAPSHOT.
Possible solution:
- Declare repository providing the artifact, see the documentation at
error for
springfox-swagger2:3.0.0-SNAPSHOT
springfox-swagger-ui:3.0.0-SNAPSHOT
springfox-spring-webflux:3.0.0-SNAPSHOT
while reimport gradle projects.
buildscript {
ext {
kotlin_version = "1.2.51"
springBootVersion = "2.0.3.RELEASE"
junitPlatformVersion = '1.0.0-M2'
junitJupiterVersion = '5.0.0-M2'
junitVintageVersion = '4.12.0-M2'
smack_version = '4.2.3'
}
repositories {
mavenLocal()
mavenCentral()
maven { url "https://repo.spring.io/milestone" }
maven { url "https://repo.spring.io/snapshot" }
maven { url "https://repo.spring.io/libs-snapshot" }
}
dependencies {
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
classpath "io.spring.gradle:dependency-management-plugin:1.0.3.RELEASE"
classpath("org.jetbrains.kotlin:kotlin-allopen:${kotlin_version}")
}
}
defaultTasks "clean", "build"
subprojects {
apply plugin: 'java'
apply plugin: 'kotlin'
apply plugin: 'kotlin-spring'
sourceCompatibility = 1.8
repositories {
maven { url "https://repo.spring.io/libs-snapshot" }
mavenLocal()
mavenCentral()
maven { url "http://archiva.hsenidmobile.com/repository/internal" }
maven { url "https://repo.spring.io/milestone" }
maven { url "https://repo.spring.io/snapshot" }
maven { url "https://repo.spring.io/libs-snapshot" }
maven { url 'http://oss.jfrog.org/artifactory/oss-snapshot-local/' }
jcenter()
}
dependencies {
compile "org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlin_version"
compile "org.jetbrains.kotlin:kotlin-reflect:$kotlin_version"
compile("org.springframework.boot:spring-boot-starter-webflux:$springBootVersion") {
exclude(module: "hibernate-validator")
}
compile("org.springframework.boot:spring-boot-starter-data-jpa:$springBootVersion")
compile("org.springframework.boot:spring-boot-starter-security:$springBootVersion")
compile("javax.servlet:javax.servlet-api:3.0.1")
compile("io.jsonwebtoken:jjwt:0.7.0")
compile("hms.common:hms-common-util:1.0.9")
compile("com.fasterxml.jackson.module:jackson-module-kotlin:2.9.0.pr4")
compile("com.fasterxml.jackson.datatype:jackson-datatype-jsr310:2.9.0.pr4")
compile("org.postgresql:postgresql:42.1.4")
compile("com.google.api-client:google-api-client:1.22.0")
compile group: 'org.springframework.plugin', name: 'spring-plugin-core', version: '2.0.0.RELEASE'
compile 'io.springfox:springfox-swagger2:3.0.0-SNAPSHOT'
compile 'io.springfox:springfox-swagger-ui:3.0.0-SNAPSHOT'
compile 'io.springfox:springfox-spring-webflux:3.0.0-SNAPSHOT'
implementation "org.igniterealtime.smack:smack-tcp:$smack_version"
implementation "org.igniterealtime.smack:smack-experimental:$smack_version"
implementation "org.igniterealtime.smack:smack-java7:$smack_version"
implementation "org.igniterealtime.smack:smack-extensions:$smack_version"
implementation "org.igniterealtime.smack:smack-im:$smack_version"
testCompile("org.junit.jupiter:junit-jupiter-api:${junitJupiterVersion}")
testCompile("org.junit.platform:junit-platform-runner:${junitPlatformVersion}")
testCompile("org.springframework.boot:spring-boot-starter-test:$springBootVersion")
testCompile("io.projectreactor:reactor-test:3.1.0.RELEASE")
runtime("tanukisoft:wrapper:3.2.3")
testRuntime("org.junit.jupiter:junit-jupiter-engine:${junitJupiterVersion}") //JUnit5
testRuntime("org.junit.vintage:junit-vintage-engine:${junitVintageVersion}") //JUnit4
}
compileKotlin {
kotlinOptions.jvmTarget = "1.8"
}
compileTestKotlin {
kotlinOptions.jvmTarget = "1.8"
}
}
add this repository
<repository>
<id>jcenter-snapshots</id>
<name>jcenter</name>
<url>http://oss.jfrog.org/artifactory/oss-snapshot-local/</url>
</repository>
it's maven syntax but you can easily translate it to gradle
Add this to your gradle build script root.
repositories {maven { url 'http://oss.jfrog.org/artifactory/oss-snapshot-local/' }}

Default buildDir for kotlin projects

I'm trying to add documentation to my project with dokka https://kotlinlang.org/docs/reference/kotlin-doc.html
I'm not quite able to figure out where the javadocs are located after doing a successful ./gradlew build.
It says there they should be in $buildDir/javadoc but I'm not sure where buidlDir is pointing to.
My build.gradle file is this:
buildscript {
repositories {
jcenter()
}
dependencies {
classpath 'com.github.jengelman.gradle.plugins:shadow:2.0.4'
}
}
plugins {
id 'org.jetbrains.kotlin.jvm' version '1.3.11'
id 'org.jetbrains.dokka' version '0.9.18'
// id("org.jmailen.kotlinter") version "1.23.1"
}
dokka {
outputFormat = 'html'
outputDirectory = "$buildDir/javadoc"
}
group 'com.github.me.dynamik'
version '1.0-SNAPSHOT'
apply plugin: 'application'
apply plugin: 'kotlin'
apply plugin: 'java'
apply plugin: 'com.github.johnrengelman.shadow'
mainClassName = 'com.github.me.dynamik.interpreter.MainEntryKt'
repositories {
mavenCentral()
jcenter()
maven { setUrl("https://dl.bintray.com/hotkeytlt/maven") }
maven {
url = uri("https://plugins.gradle.org/m2/")
}
}
configurations {
ktlint
}
dependencies {
compile "org.jetbrains.kotlin:kotlin-stdlib-jdk8"
compile 'com.github.h0tk3y.betterParse:better-parse-jvm:0.4.0-alpha-3'
// https://mvnrepository.com/artifact/junit/junit
testCompile group: 'junit', name: 'junit', version: '4.4'
implementation 'com.github.ajalt:clikt:1.7.0'
implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-core:1.2.0'
}
compileKotlin {
kotlinOptions.jvmTarget = "1.8"
}
compileTestKotlin {
kotlinOptions.jvmTarget = "1.8"
}
run {
standardInput = System.in
}
jar {
manifest {
attributes 'Main-Class': 'com.github.me.dynamik.interpreter.MainEntryKt'
}
}
test {
// Always run tests, even when nothing changed.
dependsOn 'cleanTest'
// Show test results.
testLogging {
events "passed", "skipped", "failed"
}
}
I'd love a pointer or two in the right direction.
Thank you!
In Gradle the project property buildDir points by default to the subdirectory build of your project directory.
The dokka output directory javadoc may be missing in buildDir because the dokka task has never run before. Your build.gradle file seems not to have any dependencies on the dokka task or its output, so it isn't triggered when you're running build or assemble tasks. You can try running it explicitly: ./gradlew dokka or add a dependency on that task to some other lifecycle task, e.g
assemble.dependsOn(dokka)

protobuf gradle plugin does not compile

I'm trying to compile protobuf files using the gradle plugin, but I get the following error:
java.io.IOException: Can't write [/Users/elavi/dev/sdk3/android/showcaseapp/build/intermediates/multi-dex/debug/componentClasses.jar]
(Can't read [/Users/elavi/.gradle/caches/modules-2/files-2.1/com.google.protobuf/protobuf-java/3.0.0/6d325aa7c921661d84577c0a93d82da4df9fa4c8/protobuf-java-3.0.0.jar(;;;;;;**.class)]
(Duplicate zip entry [protobuf-java-3.0.0.jar:com/google/protobuf/ExperimentalApi.class]))
Not sure why this happens...
The protobuf files are generated correctly, as expected, but then the final step fails with this weird error.
This is my gradle file:
apply plugin: 'com.android.library'
apply plugin: 'com.google.protobuf'
apply plugin: 'idea'
group = GROUP
version = VERSION_NAME
apply from: 'versioning.gradle'
buildscript {
repositories {
mavenCentral()
}
}
android {
compileSdkVersion 26
buildToolsVersion '26.0.2'
flavorDimensions "default"
defaultConfig {
minSdkVersion 15
targetSdkVersion 26
versionCode buildVersionCode()
versionName VERSION_NAME
consumerProguardFiles 'tangram-proguard-rules.txt'
}
// Add proto files location to be used with the protobuf plugin
sourceSets {
main {
proto {
srcDir '../../common/vendored/proto'
}
}
}
}
dependencies {
compile 'com.google.protobuf:protobuf-lite:3.0.0'
compile 'io.grpc:grpc-stub:1.6.1'
compile 'io.grpc:grpc-protobuf:1.0.0-pre2'
compile 'javax.annotation:javax.annotation-api:1.2'
compile 'com.squareup.okhttp3:okhttp:3.9.0'
compile 'com.android.support:support-annotations:27.0.0'
implementation project(':core')
}
// Protobuf configuration. Taken from the documentation: https://github.com/google/protobuf-gradle-plugin
protobuf {
protoc {
artifact = 'com.google.protobuf:protoc:3.0.0' } plugins {
javalite {
artifact = 'com.google.protobuf:protoc-gen-javalite:3.0.0'
}
grpc {
artifact = 'io.grpc:protoc-gen-grpc-java:1.0.0-pre2'
} } generateProtoTasks {
all().each { task ->
task.builtins {
remove java
}
task.plugins {
javalite { }
grpc {
option 'lite'
}
}
} } generatedFilesBaseDir = "$projectDir/build/gen" }
clean { delete protobuf.generatedFilesBaseDir }
idea { module {
sourceDirs += file("${protobuf.generatedFilesBaseDir}/main/java");
sourceDirs += file("${protobuf.generatedFilesBaseDir}/main/grpc"); } }
//apply from: file('gradle-mvn-push.gradle')
I simply added what's written in the protobuf readme (https://github.com/google/protobuf-gradle-plugin), didn't do any fancy stuff...
maybe you should remove compile 'com.google.protobuf:protobuf-lite:3.0.0' entry on dependencies section, also you have duplicated entries and some config on last versions are missing. For other side maybe the path for proto sources have issues, my protos are src/main/proto but I only declared proto alone. My brief config is next:
app build.gradle:
apply plugin: 'com.google.protobuf'
android {
...
sourceSets {
main {
proto {
}
}
}
...
configurations.all {
resolutionStrategy.force 'com.google.code.findbugs:jsr305:1.3.9'
}
}
dependencies {
implementation fileTree(include: ['*.jar'], dir: 'libs')
implementation 'com.android.support:appcompat-v7:27.1.1'
implementation 'io.grpc:grpc-okhttp:1.10.0'
implementation 'io.grpc:grpc-protobuf-lite:1.10.0'
implementation 'io.grpc:grpc-stub:1.10.0'
implementation 'javax.annotation:javax.annotation-api:1.2'
// full protobuf (optional)
// protobuf 'com.google.protobuf:protobuf-java:3.4.0'
...
}
protobuf {
protoc {
artifact = "com.google.protobuf:protoc:3.0.2"
}
plugins {
grpc {
artifact = 'io.grpc:protoc-gen-grpc-java:1.1.2'
}
javalite {
artifact = "com.google.protobuf:protoc-gen-javalite:3.0.0"
}
}
generateProtoTasks {
all().each { task ->
task.plugins {
javalite {}
grpc {
// Options added to --grpc_out
option 'lite'
}
}
}
}
generatedFilesBaseDir = "$projectDir/build/generated"
}
main project build.gradle:
buildscript {
repositories {
google()
jcenter()
}
dependencies {
classpath 'com.android.tools.build:gradle:3.0.0'
classpath "com.google.protobuf:protobuf-gradle-plugin:0.8.2"
...
}
}