Gradle - FatJar - Could not find or load main class
Asked Answered
P

4

27

I know that question was asked a lot and has many answers, but i still get it and I don't understand why...

I am trying to generate a .jar from a projet with dependencies with gradle.

I have a class src/main/java/Launcher.java, in which I have my main method.

there is my build.gradle

plugins {
    id 'java'
    id 'application'
}

version '1.0-SNAPSHOT'
sourceCompatibility = 1.8
mainClassName = 'Launcher'

repositories {
    mavenCentral()
}

dependencies {
    compile 'commons-io:commons-io:2.1'
    compile 'io.vertx:vertx-core:3.4.0'
    compile 'io.vertx:vertx-web:3.4.0'
    compile 'com.google.code.gson:gson:1.7.2'
    compile "com.auth0:java-jwt:3.1.0"
    compile 'org.mongodb:mongo-java-driver:3.4.1'
    compile 'com.google.guava:guava:24.1-jre'
    compile 'commons-io:commons-io:2.6'
}

jar {
    manifest {
        attributes "Main-Class": mainClassName
    }

    from {
        configurations.compile.collect { it.isDirectory() ? it : zipTree(it) }
    }
}

I use $>gradle assemble to generate my jar then $>java -jar path/to/my/.jar And i get the error "could not find or load main class Launcher"...

I dont understand why, when I look in the .jar, I have Launcher class and in META-INF I have my manifest

screenshot

Sorry for still asking this question in 2018 but i'm loosing my mind trying to figure out what's wrong. I hope somone will have the answer !

Profess answered 21/7, 2018 at 10:33 Comment(2)
You said you are using "assemble" to make the jar. What about "build"?Denier
From what I read online, assemble seemed to be enough for what I neededProfess
P
59

I reproduced your issue locally.

Just add exclude 'META-INF/*.RSA', 'META-INF/*.SF', 'META-INF/*.DSA' to the jar task.

This will exclude the signatures of interfering dependencies.

Example:

jar {
    manifest {
        attributes "Main-Class": mainClassName
    }

    from {
        configurations.compile.collect { it.isDirectory() ? it : zipTree(it) }
    }
    exclude 'META-INF/*.RSA'
    exclude 'META-INF/*.SF'
    exclude 'META-INF/*.DSA'
}
Pacifically answered 21/7, 2018 at 12:29 Comment(9)
@Hadrien: Make sure your app really works as expected. Bouncycastle is a crypto provider which requires a signature, therefore removing the signature makes all code parts fail which depend on the BouncyCastle JCE.Vitek
After a long time searching, this also solved it for me, thanks!Ursel
Thank you! Thank you! Thank you!Dutybound
Works like a charmCounterpoise
Wow, can't believe the message is non informative and that there are no tools, which could lead to point this out. Have spent a whole day on looking on related questions, then found this only by accident. Thanks!Dayfly
Thanks! Can you explain this sentence a little more "This will exclude the signatures of interfering dependencies." ? What is interfering dependency? What's wrong with them ?Latex
OMG, I spent so much time on this! thanks a lotPorscheporsena
Thank you so muchHegumen
In my case, exclude 'META-INF/*.SF' was sufficientTimbale
V
14

You are running into the one major problem when building a FAT JAR:

One of your source JARs is signed and merging it into one fat jar destroys the signature.

It looks like Java recognizes that there are unsigned classes and ignores everything but the signed classes. As all classes that do not belong to the signed library are unsigned (like your Launcher class) they are ignored and therefore can't be loaded.

In your case it looks like that the dependency org.bouncycastle:bcprov-jdk15on:1.55 of com.auth0:java-jwt:3.1.0 is the signed jar file. Because my sample project correctly executes Launcher when I uncomment this dependency.

Bouncy castle is a crypto provider that requires a valid signature otherwise it will not run from my experience. Therefore it is impossible to create a fat jar for your project that just contains all classes.

You can try to create a fat jar with everything except Bouncycastle and ship Bouncycastle JAR seperatly.

Or a fat jar that contains all the required JAR files inside (JAR inside JAR) and that uses a special class loader that is able to load classes from within such a JAR inside a JAR. See for example: https://mcmap.net/q/47040/-using-gradle-to-build-a-jar-with-dependencies

Vitek answered 21/7, 2018 at 12:4 Comment(1)
Thank you for the explainations, the problem got solvedProfess
R
1

Try to exclude .SF .DSA .RSA files, example below, Nipun

Hope this works out for you

task customFatJar(type: Jar) {
  baseName = 'XXXXX'
  from { configurations.compile.collect { it.isDirectory() ? it : zipTree(it) } 
  }
  with jar

  exclude "META-INF/*.SF"
  exclude "META-INF/*.DSA"
  exclude "META-INF/*.RSA"

  manifest {
    attributes 'Main-Class': 'com.nipun.MyMainClass'
  }
}
Radically answered 19/8, 2018 at 18:41 Comment(0)
W
1

Adding

exclude 'META-INF/*.RSA'
exclude 'META-INF/*.SF'
exclude 'META-INF/*.DSA'

Fixed my issue.

Whipcord answered 16/11, 2022 at 22:59 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.