Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Gradle - FatJar - Could not find or load main class

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 !

like image 494
Hadrien Avatar asked Jul 21 '18 10:07

Hadrien


3 Answers

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'
}
like image 130
avolkmann Avatar answered Nov 10 '22 13:11

avolkmann


You are running into the 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://stackoverflow.com/a/33420518/150978

like image 27
Robert Avatar answered Nov 10 '22 14:11

Robert


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'
  }
}
like image 1
Nipun Avatar answered Nov 10 '22 13:11

Nipun