Reputation: 11
I have a Java project with multiple dependencies that I would like to package into a fat jar with Gradle using Kotlin DSL.
When I run ./gradlew jar
, the build succeeds, but it cannot find the main class when I try to run it:
$ ./gradlew jar
BUILD SUCCESSFUL in 1s
2 actionable tasks: 2 executed
$ java -jar build/libs/myapp-0.0.1-SNAPSHOT.jar
Error: Could not find or load main class mypackage.Hello
Caused by: java.lang.ClassNotFoundException: mypackage.Hello
$ jar xf build/libs/myapp-0.0.1-SNAPSHOT.jar META-INF/MANIFEST.MF
$ cat META-INF/MANIFEST.MF
Manifest-Version: 1.0
Main-Class: mypackage.Hello
$ jar -tf build/libs/myapp-0.0.1-SNAPSHOT.jar | grep mypackage 1
mypackage/
mypackage/Hello.class
Here is the full build.gradle.kts
file:
group = "myapp"
version = "0.0.1-SNAPSHOT"
java {
sourceCompatibility = JavaVersion.VERSION_1_8
targetCompatibility = JavaVersion.VERSION_1_8
withSourcesJar()
}
plugins {
java
}
repositories {
mavenCentral()
maven {
url = uri("https://mvnrepository.com/artifact/com.microsoft.azure/azure-storage")
}
}
dependencies {
implementation("com.azure:azure-storage-blob:12.12.0")
}
val mainClassName = "mypackage.Hello"
tasks.jar {
duplicatesStrategy = DuplicatesStrategy.INCLUDE
manifest.attributes.apply {
put("Class-Path", configurations.runtimeClasspath.get().asPath)
put("Main-Class", mainClassName)
}
from(configurations.compileClasspath.get().map { if (it.isDirectory) it else zipTree(it) })
}
tasks.test {
useJUnitPlatform()
}
And a link to my repo: https://github.com/darkasphalt/myapp
Upvotes: 1
Views: 2807
Reputation: 1416
Check the content of jar. The problem is, that you include all the contents of the the libs. This also also adds files from the java module system like the module-info.class
. This may hide your Main class.
Your main works, if you:
a) Remove the import
implementation("com.azure:azure-storage-blob:12.12.0")
or
b) Remove the classpath config:
from(configurations.compileClasspath.get().map { if (it.isDirectory) it else zipTree(it) })
Than a simple java -jar myapp-0.0.1-SNAPSHOT.jar
will print out the:
Hello
To solve the problem of packaging a fat jar the right way, you might use the ShadowJar plugin. With this setup, the bundled jar works:
import com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar
group = "myapp"
version = "0.0.1-SNAPSHOT"
plugins {
java
application
id("com.github.johnrengelman.shadow").version("7.0.0")
}
java {
sourceCompatibility = JavaVersion.VERSION_1_8
targetCompatibility = JavaVersion.VERSION_1_8
withSourcesJar()
}
repositories {
mavenCentral()
maven {
url = uri("https://mvnrepository.com/artifact/com.microsoft.azure/azure-storage")
}
}
application() {
mainClass.set("mypackage.Hello")
}
dependencies {
implementation("com.azure:azure-storage-blob:12.12.0")
}
// Configure Shadow to output with normal jar file name:
tasks.named<ShadowJar>("shadowJar").configure {
minimize()
}
tasks {
build {
dependsOn(shadowJar)
}
}
tasks.test {
useJUnitPlatform()
}
Upvotes: 1