Gradle - FatJar - 找不到或加载主类

27

我知道这个问题已经被问了很多次并且有很多答案,但是我仍然不理解为什么...

我正在尝试使用gradle从一个带有依赖关系的项目中生成一个.jar

我有一个类src/main/java/Launcher.java,其中有我的main方法。

这是我的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) }
    }
}

我使用 $>gradle assemble 命令生成我的jar包,然后运行 $>java -jar path/to/my/.jar 命令时,出现了错误 "could not find or load main class Launcher"...

我不明白为什么,在我的.jar文件中,我有Launcher类,并且在META-INF中我有我的清单。

screenshot

非常抱歉,我知道这个问题早在2018年就被问过了,但我正在尝试找出问题所在,却束手无策。希望有人能够回答!


你说你正在使用 "assemble" 来制作 jar 包。那么 "build" 呢? - Alexiy
从我在网上阅读的内容来看,汇编似乎对我所需的足够了。 - Hadrien
4个回答

57

我在本地复现了您的问题。

只需将exclude 'META-INF/*.RSA', 'META-INF/*.SF', 'META-INF/*.DSA'添加到jar任务中。

这将排除干扰依赖项的签名。

例如:

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

3
请确认您的应用程序能够正常工作。Bouncycastle是一个加密提供者,需要签名,因此删除签名会导致所有依赖于BouncyCastle JCE的代码部分失败。 - Robert
1
经过长时间的搜索,这个也为我解决了问题,谢谢! - theferrit32
2
谢谢!谢谢!谢谢! - tmp
谢谢!你能再解释一下这句话吗:"This will exclude the signatures of interfering dependencies."?什么是干扰依赖项?它们有什么问题吗? - fuat
哎呀,我在这上面花了太多时间了!非常感谢。 - schirrmacher
显示剩余4条评论

13
你在构建一个FAT JAR时遇到了一个主要问题:
其中一个源JAR已经签名,将其合并到一个fat jar中会破坏签名。
看起来Java识别到有未签名的类,并忽略除签名类以外的所有内容。由于所有不属于签名库的类都是未签名的(比如你的Launcher类),它们被忽略,因此无法加载。
在你的情况下,看起来依赖项com.auth0:java-jwt:3.1.0的org.bouncycastle:bcprov-jdk15on:1.55是已签名的jar文件。因为当我取消注释这个依赖项时,我的示例项目可以正确执行Launcher。
Bouncy castle是一个加密提供者,需要有效的签名才能正常运行,根据我的经验。因此,对于只包含所有类的项目来说,创建一个fat jar是不可能的。
你可以尝试创建一个除了Bouncycastle之外的fat jar,并单独提供Bouncycastle JAR文件。
或者一个包含所有所需JAR文件的大型JAR文件(JAR内部有JAR),并且使用特殊的类加载器,能够从这样的JAR内部加载类。例如,请参考:https://dev59.com/iW445IYBdhLWcg3wappH#33420518

感谢您的解释,问题已经解决。 - Hadrien

1
尝试排除 .SF .DSA .RSA 文件,示例如下,Nipun。
希望这对你有用。
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'
  }
}

0

添加

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

问题已解决。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接