darkasphalt
darkasphalt

Reputation: 11

Gradle Kotlin DSL: could not find or load main class

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

Answers (1)

Tobse
Tobse

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.

Simple Fix

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

Setup with ShadowJar

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

Related Questions