使用jarsigner重复输入module-info.class对Java 11 jar进行签名

时间:2018-12-23 08:05:54

标签: java jarsigner java-11 jar-signing

嗨,我是java模块的新手,所以这可能是一个愚蠢的问题。

我试图用keystore签名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) }
    }

}

我知道我不应该发布屏幕截图,但这是由档案管理器打开的罐子 Archive manager screenshot

有7个module-info.class文件,第一个文件是在18年12月23日(今天)生成的,其余的都是05年11月5日的文件,我记得那天升级到了Java 11,

因此,这些是从我的依赖项中添加的,如何将它们集成到一个类中?还是还有其他选择来签名罐子?

再次,这是来自菜鸟。

[编辑] 如果您正在寻找完整的源代码,请访问GitHub-> https://github.com/CodingOtaku/Animu-Downloaderu

1 个答案:

答案 0 :(得分:3)

根据您在运行时发布的build.gradle内容:

./gradlew jar

您正在创建一个胖子/影子jar,它将所有依赖项(包括模块化的依赖项)捆绑在一个大的jar中。此过程将从每个jar(类和资源)中提取所有文件到libs文件夹中,最后将其压缩到项目的影子jar中。

模块化依赖项(至少JavaFX jar)在其jar文件中包含一个module-info.class文件。因此,这些将被添加到libs文件夹中。

由于jar任务的结果,并且取决于您的平台,您最终只能获得其中一个文件(如果将具有相同名称的文件粘贴到一个文件中,则只能添加第一个或最后一个文件)文件)或所有文件(如果您保留了所有具有相同名称的文件,因为这似乎是您的情况)。

无论哪种方式,由于您正在创建一个胖子罐,因此将其运行为:

java -jar my-fat-jar.jar

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

解决方案

一个简单的解决方案是从胖罐中排除模块信息文件:

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

跨平台jar

请注意,您releasing的jar并不是跨平台的,因为它仅包含Linux的本机库。

可以在here的非模块化应用程序-> Gradle->跨平台jars中找到一个创建跨平台jar的选项。

jlink

或者,您可以考虑使用jlink进行分发,因为您的应用已经是modular

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

请参见doc的“用Gradle模块化”一节,并使用jlink任务,或者尝试使用badass-jlink-plugin

jpackage

在Java 12的jpackage工具中有preview,使用它可以为每个平台创建一个安装程序。