使用jarsigner签名Java 11 jar文件时出现重复条目module-info.class。

9

你好,我是一个新手,对于Java模块还不是很了解,所以我的问题可能有点儿愚蠢。

我试图使用密钥库对我的jar文件进行签名,但是出现了以下错误:

user@Ubuntu:libs(master)$ jarsigner -keystore keyStoreFileName Test.jar alias
Enter Passphrase for keystore: 
jarsigner: unable to sign jar: java.util.zip.ZipException: duplicate entry: module-info.class

我找不到任何关于如何避免这个问题的文档。

所以我运行了 jar -tf 命令来检查 jar 文件的内容,确认它确实有多个 module-info.class 文件。

有没有什么选项可以将它们合并?如何操作?

我的 module-info.java 文件包含以下内容。

module module_name {
    requires java.desktop;
    requires java.prefs;
    requires javafx.controls;
    requires javafx.fxml;
    requires javafx.web;
    requires org.jsoup;
    opens com.test.apps to javafx.fxml;
    exports com.test.apps;
}

我正在使用Gradle创建JAR文件,操作如下:

jar {
    manifest {
        attributes 'Main-Class': 'com.test.apps.Main'
        attributes 'Application-Name': 'Test'
    }

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

}

我知道我不应该发布截图,但这里是用存档管理器打开的jar文件。 Archive manager screenshot 有7个module-info.class文件,第一个是在23-Dec-18(今天)生成的,其余的都来自于05-Nov-18,我记得那天升级到了Java 11,
所以这些是从我的依赖项中添加的,如何将它们集成到一个类中?或者是否有其他选项可以签名一个jar?
再次说明,这是一个新手。
[编辑] 如果你正在寻找完整的源代码,它在GitHub上->https://github.com/CodingOtaku/Animu-Downloaderu

你的jar文件中为什么有多个module-info.class文件? - Naman
@nullpointer 我不知道,它是那样生成的。也许它正在从依赖项中添加所有的modules-info.class。我会添加一张截图。 - Coding Otaku
1个回答

12

根据你发布的build.gradle内容,当你运行:

./gradlew jar

你正在创建一个fat/shadow jar,将所有依赖项(包括模块化的依赖项)打包成一个大的jar文件。此过程将每个jar文件中的所有文件(类和资源)提取到libs文件夹中,并最终压缩成项目的shadow jar。
模块化依赖项(至少JavaFX jars)在其jar文件中包含一个module-info.class文件。因此,这些将添加到libs文件夹中。
由于jar任务的结果,根据您的平台,您可能只会得到其中一个文件(如果将具有相同名称的文件粘贴到一个文件中,则为第一个或最后一个添加的文件),或者全部文件(即使是带有相同名称的文件也保留,因为这似乎是您的情况)。
无论哪种方式,由于您正在创建一个fat jar,您将以以下方式运行它:
java -jar my-fat-jar.jar

而为此,您根本不需要任何模块。

解决方案

因此,一个简单的解决方案是从您的fat jar中排除module-info文件:

jar {
    manifest {
        attributes 'Main-Class': 'your.main.class'
    }
    from {
        exclude '**/module-info.class'
        configurations.compile.collect { it.isDirectory() ? it : zipTree(it) }
    }
}

跨平台 jar 包

请注意,您正在 发布 的 jar 包不是跨平台的,因为它只包含了 Linux 平台的本地库。

创建跨平台 jar 包的一种选择可以在 此处 找到,选择“非模块化应用程序” -> “Gradle” -> “跨平台 jar 包”。

jlink

或者,您可以考虑使用 jlink 进行分发,因为您的应用程序已经是 模块化 的。

在这种情况下,您将为特定平台生成一个自定义镜像。您可以考虑为每个平台创建一个镜像。

请参阅 文档 中的“Gradle 模块化”部分,并使用 jlink 任务,或尝试使用 badass-jlink-plugin

jpackage

Java 12 中有一个 jpackage 工具的 预览 版本。使用它,您可以为每个平台创建一个安装程序。


谢谢!这正是我在寻找的! - Coding Otaku

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