Gradle - FatJar - Could not find or load main clas

2019-02-13 15:25发布

问题:

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

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 !

回答1:

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.



回答2:

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



回答3:

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'
  }
}