StackHawk
๏ƒ‰

How to Run Standalone Kotlin with Gradle

Topher Lamey   |   Jan 15, 2021

Share on LinkedIn
Share on X
Share on Facebook
Share on Reddit
Send us an email
Topher Lamey Blog Image
Recently we wanted to add a specific kind of alerting to some of our build process via a third-party product. As part of that, we needed to run some of our Kotlin code in the third-party product as a standalone application. The third party had a limitation in that they only support this kind of execution usingjava -jar file.jar
directly with a single jar file.Luckily,java
easily supports this via jar files with:
  • An applicationโ€™s entry point via theMain-Class property in the jarโ€™s manifest file
  • Packing any third-party classes in the jar (AKA a โ€˜fatโ€™ jar).

We use Gradle for our build tool, and have used the application
plugin to build and run arbitrary standalone applications. In this case, we already had the class defined in Kotlin with a main function used by Gradleโ€™sapplication
plugin that we wanted to run in this new third-party system.Our main class is in a filecom/stackhawk/example/Main.kt
:

fun main(args: Array<String>) {
    println("Hello World!")
}

Note that unlike Java, Kotlin takes that file name and modifies for Java referencing in Gradle.

Ourbuild.gradle.kts
file then uses it with theapplication
plugin like this:
plugins {
    application
}

application {
    mainClassName = "com.stackhawk.example.MainKt" // Really Main.kt
}

With that, we can do this at the shell:

> ./gradlew run
Hello World!
We canโ€™t use Gradle in this third-party system, so we need to produce a jar file with theMain-Class
property set in the manifest to the same class. We can do that using the Gradlejar
task:
tasks.jar { // could also be a new task rather than the default one
    manifest {
        attributes["Main-Class"] = "com.stackhawk.example.MainKt"
    }
}

But we also have a bunch of third-party dependencies that we need to pack into that jar file. Luckily, thejar
task can be expanded to include them in our jar.

tasks.jar { // could also be a new task rather than the default one
    manifest {
        attributes["Main-Class"] = "com.stackhawk.example.MainKt"
    }

    from(sourceSets.main.get().output)
    dependsOn(configurations.runtimeClasspath)
    from({
        configurations.runtimeClasspath.get().filter { it.name.endsWith("jar") }.map { zipTree(it) }
    })
}

Now we can do this:

> ./gradlew build
> java -jar build/libs/example-0.0.1.jar
Hello World!

Which is exactly how the third-party system wants to run Java/Kotlin applications.

Hereโ€™s a complete example that supports both./gradlew run
andjava -jar $OUTPUT_JARFILE
:

val main = "com.stackhawk.example.MainKt"

application {
    mainClassName = main
}

tasks.jar {
    manifest {
        attributes["Main-Class"] = main
    }

    from(sourceSets.main.get().output)
    dependsOn(configurations.runtimeClasspath)
    from({
        configurations.runtimeClasspath.get().filter { it.name.endsWith("jar") }.map { zipTree(it) }
    })
}

Once we had this set up in the project, we were able to generate a jar that worked as expected in the third-party alerting system. Since then, weโ€™ve had other reasons, such as one-off and scheduled jobs, to use a jar in this manner and this Gradle set up has worked for those uses cases as well.

Blog Banner - Ready to Test Your App

More Hawksome Posts

Discover the Best API Discovery Tools in 2025

Discover the Best API Discovery Tools in 2025

APIs power todayโ€™s software, but with AI tools accelerating development, many organizations donโ€™t even know how many APIs they haveโ€”or how secure they are. Shadow, zombie, and rogue APIs can quietly expand your attack surface, leaving critical vulnerabilities unchecked. Thatโ€™s why modern API discovery tools are essential. This guide breaks down what API discovery is, why it matters more than ever in 2025, and how to choose the right tool to secure your entire API landscape.