生成的JAR会向主类抛出

时间:2018-06-19 17:56:47

标签: java intellij-idea jar

我正在使用IntelliJ IDEA创建一个JAR。我为库JAR选择了“来自具有依赖项的模块中的JAR”和“提取到目标JAR”-生成的JAR看起来还不错:

myJar.jar
  |
  +- META-INF
  |  +- MANIFEST.MF
  +- com
  |  +- my
  |     +- package
  |        +- Main.class
  +- some dependencies...

我检查了两次:所有必需的依赖项都存在。 Main-Class中的MANIFEST.MF字段指向正确的主类(在本示例中为com.my.package.Main)。我已经在存档工具中打开文件,并使用

对其进行了检查
jar tf myJar.jar

都表明所需的类可用(也Main.class)。我不需要IntelliJ向导中的Classpath字段,因为我不需要任何外部库。但是,当我发出

java -jar myJar.jar

它引发以下异常:

Error: could not find or load main class com.my.package.Main
Caused by: java.lang.ClassNotFoundException: com.my.package.Main

我遵循了this guide by JetBrains ,并且IntelliJ自动添加了来自Maven pom.xml的所有依赖关系以将其提取到JAR中,这是正确的。

我是否缺少在此处配置的内容?为什么不起作用?

(注意:当我为库JAR选择“复制到输出文件夹并通过清单链接”时,从该项目生成JAR也不起作用。)

(注2:遗憾的是,不能使用maven-assembly-plugin,因为我引用了其他IntelliJ工作区模块,这些模块随后将不包含在内。)


更新:按原样工作还显示以下现象:当我解压缩JAR并执行

java -cp . com.my.package.Main

在创建的目录中,它可以正常工作,考虑到Java拒绝加载它,这很奇怪...

1 个答案:

答案 0 :(得分:0)

在我的情况下,由于某些签名的JAR依赖项,我的JAR无法正常工作。

这些JAR带有签名和密钥文件,当您嵌入签名的JAR时也会提取它们。基本上没有删除它们的风险,但这是您的JAR可能无法正常工作的众多原因之一。

如何从JAR中删除此类签名?
我正在描述Linux / Darwin的以下步骤,但我认为Windows也有类似的方法。

  1. 解压缩您的JAR。
    由于JAR只不过是简单的ZIP存档,因此您可以使用2018-07-02 20:25:08.208812 <br> 2018-07-02 21:25:08.208812<br> 2018-07-02 22:25:08.208812<br> 2018-07-02 23:25:08.208812<br> 2018-07-02 24:25:08.208812<br> 2018-07-02 01:25:08.208812<br> 2018-07-02 02:25:08.208812<br> 2018-07-02 03:25:08.208812<br> 2018-07-02 04:25:08.208812<br> 2018-07-02 05:25:08.208812<br> 2018-07-02 06:25:08.208812<br> 2018-07-02 07:25:08.208812<br> 2018-07-02 08:25:08.208812<br> 2018-07-02 09:25:08.208812<br> 2018-07-02 10:25:08.208812<br> 2018-07-02 11:25:08.208812<br> 2018-07-02 12:25:08.208812<br> 2018-07-02 13:25:08.208812<br> 2018-07-02 14:25:08.208812<br> 2018-07-02 15:25:08.208812<br> 2018-07-02 16:25:08.208812<br> 2018-07-02 17:25:08.208812<br> 2018-07-02 18:25:08.208812<br> 2018-07-02 19:25:08.208812<br> 2018-07-02 20:25:08.208812<br>

    unzip

    mkdir temporaryDirectory unzip myJar.jar -d temporaryDirectory/ 选项是可选的,但是由于它设置了目标目录,因此有助于保持目录结构整洁。

  2. 找到签名文件。
    签名文件(或密钥)位于-d目录中,因此请在此处进行更改:

    META-INF/

    接下来,我们需要找到麻烦的文件。它们具有文件扩展名cd temporaryDirectory/META-INF/ (用于签名)和.SF的密钥文件:

    .DSA
  3. 删除(或重命名)签名和密钥文件。
    重命名这些文件几乎没有好处,您可以稍后再恢复它们(无论出于何种原因),删除它们也可以解决这个问题,但风险更高:

    • 删除:

      ll | grep '.DSA\|.SF'
      
    • 重命名:

      rm signature.DSA signature.SF
      # Either enter the name of the files
      # instead of 'signature' or use * to delete any:
      # rm *.DSA *.SF
      
  4. 重新打包JAR。
    仍在rename 's/\.DSA$/.DSA.old/' * # Append ".old" to all .DSA files rename 's/\.SF$/.SF.old/' * # Append ".old" to all .SF files 中,我们可以重新打包JAR使其工作:

    temporaryDirectory/

    说明:

    • cd ../ # If you're still in temporaryDirectory/META-INF jar cfm ../myWorkingJar.jar ./META-INF/MANIFEST.MF -C ./ .
      jar cfm是Java的内置JAR构建器。用jar调用它意味着我们要创建一个JAR,c代表输出文件(我们在下面指定),而f代表我们想要的m采用。如果省略MANIFEST.MF,则m会将一个空白的jar写入JAR。
    • MANIFEST.MF
      这是我们要将JAR输出到的路径。它属于我们先前指定的../myWorkingJar.jar
    • f
      这是我们要使用的清单文件。它属于./META-INF/MANIFEST.MF的{​​{1}}。
    • m
      这意味着我们的cfm文件位于此目录(-C ./)中。
    • .class(最后一个参数)
      这表明我们要将此目录添加到JAR。

    如果要详细描述.的工作,可以使用.而不是jarcvfm表示详细信息)从上方发出命令。

  5. 验证它是否有效。
    全部设置好了,现在您可以通过发出

    来检查您的JAR是否正常运行
    cfm
  6. 删除临时目录。
    由于您已经完成了JAR的修复,因此可以安全地删除我们创建的临时目录(和/或“损坏的” JAR)。

我已经创建了一个简单的BASH脚本,该脚本可以“自动”完成该过程,只需一点点:

v

我希望这可以帮助人们也遇到这个问题。