【问题标题】:How to obtain a package version from the JAR's manifest, using the getImplementationVersion() method of the Package class如何使用 Package 类的 getImplementationVersion() 方法从 JAR 的清单中获取包版本
【发布时间】:2016-07-05 12:56:31
【问题描述】:

当我准备部署我的程序时,我将它与 Eclipse jar-in-jar 类加载器一起打包到一个 JAR 中。当我的程序从 JAR 运行时,我需要知道一个包的版本,但我无法从 jar 的清单中以一种简单而“诚实”的方式获取它。 清单如下所示:

 Manifest-Version: 1.0
 Created-By: 1.8.0_73-b02 (Oracle Corporation)
 Main-Class: org.eclipse.jdt.internal.jarinjarloader.JarRsrcLoader
 Rsrc-Main-Class: com.domain.sp2.controller.Controller
 Rsrc-Class-Path: ./ jar-in-jar-loader.zip javahelp-2.0.05.jar json-simple-1.1.1.jar
 Class-Path: .

 Name: com/domain/sp2/controller/
 Implementation-Version: 19

为了获取包的实现版本,我尝试使用最简单直接的方式:

package com.domain.sp2.controller;
public class Controller {
...
   public static String getBuildNumber() throws IOException {
     Package pckg = Controller.class.getPackage();
     pr(pckg.getName());    // prints "com.domain.sp2.controller", as expected 
     return pckg.getImplementationVersion();   // returns null
   }  
...
}

根据http://docs.oracle.com/javase/tutorial/deployment/jar/packageman.htmlhttp://docs.oracle.com/javase/8/docs/api/java/lang/Package.html#getImplementationVersion--(和其他来源),它应该返回“19”,但它返回null。对于 JRE 库的包,它返回正确的值。也许我错过了关于如何在清单中命名包的细节,或者原因与JarRsrcLoader 有关 - 可能是它需要一些特殊的语法来处理包。我也试过".com/domain/...""/com/domain/..."".../controller",甚至"rsrc:./com/domain..."作为清单中的包名——都没有成功。我可以使用其他方式,例如将清单加载为流并使用 Manifest 类对其进行解析,但我想了解使用 getImplementationVersion() 方法的正确方法是什么。

【问题讨论】:

  • 这已经有答案here
  • 是的,我确定。我在 JAR 中看到它,在正确的位置 (.META-INF/),我可以以编程方式阅读它(包括实施版本)。当 getImplementationVersion() 存在时,我只是不想加载清单并解析它。
  • @svasa,这不是我问题的答案。我没有问如何阅读清单。我的问题是“如何使用 getImplementationVersion() 方法”。我应该更清楚地表达这个问题。我会编辑它。

标签: java eclipse jar


【解决方案1】:

您可以从 classLoader 中读取清单文件并获取您需要的值,如下所示:

URLClassLoader cl = (URLClassLoader) YOUR_CLASS.class.getClassLoader();
try {
  URL url = cl.findResource("META-INF/MANIFEST.MF");
  Manifest manifest = new Manifest(url.openStream());
  Attributes mainAttributes = manifest.getMainAttributes();
  String implVersion = mainAttributes.getValue("Implementation-Version");

  System.out.println(implVersion);
} catch (IOException E) {
      // handle
}

【讨论】:

  • 是的,我可以阅读清单(正如我在问题中提到的那样),但我想了解 getImplementationVersion() 方法。为什么它对我不能正常工作?不过还是谢谢你的回复。
  • @m.vokhm 关于为什么它不起作用可能是因为清单没有您想要的信息。如果我执行Enumeration<URL> resources = MainApp.class.getClassLoader() .getResources("META-INF/MANIFEST.MF"); 并循环遍历元素,我只会得到Java 的官方清单(我不知道如何命名它们),例如检索到的第一个:jar:file:/usr/share/java/java-atk-wrapper.jar!/META-INF/MANIFEST.MF 。如果我打开此清单,则没有 Implementation-Version 字段。在查看了采用 ManifestPackage 私有构造函数后,我想到了这一点。
  • @m.vokhm 现在我可以开始工作了,我更了解它是如何工作的。您是从 IDE 还是从生成的 jar 尝试 getImplementationVersion ?因为从 IDE 中没有 Manifest(所以 getImplementationVersion 将返回 null),所以您只会在“启动真正的 jar 后”得到它。这个 jar 有一个 Manifest,根据你生成 jar 的方式,它可能包含版本,否则你仍然会得到 null(但你可以在这种情况下添加它)
【解决方案2】:

解决了!至少对我来说 :) 您需要确保相关包仅位于一个 JAR 中,并且 JAR 具有正确的清单。

有道理,因为您查询一个包的版本,如果该包存在于许多 JAR 中,所有 JAR 都具有不同或部分未设置的实现版本,那么 JVM 应该返回什么?

【讨论】:

  • 但我无法理解我的 JAR/代码有什么问题。该包仅在一个 jar 中(在我的情况下它是一个 JAR)。清单看起来不错,至少我在那里没有看到任何不好的东西(它在原始帖子中被引用)。不过getName() 返回正确的名称,getImplementationVersion() 返回null。 Java 7 和 8、x32 和 x64、Windows。
【解决方案3】:

请确保清单末尾有换行符。 如果末尾没有换行符,getImplementationVersion() 将返回null

参考:http://docs.oracle.com/javase/7/docs/technotes/guides/jar/jar.html

【讨论】:

  • 好的,谢谢。清单是由 Ant 制作的,但我已经检查过了 - 换行符存在,甚至其中两个 :)
【解决方案4】:

我在 Eclipse 中遇到了同样的问题。 问题来自 Eclipse jar-in-jar 类加载器。简单地说,不要在 jar 方法中使用外部库的包来生成 jar,而是使用将外部库提取到 jar 中的方法,它应该可以工作。

【讨论】:

    【解决方案5】:

    我在我的 IDE (Eclipse) 中发现了这个问题,因为从 IDE 中运行没有使用 jar 中生成的 Manifest。为了查看正确的行为,我只是去计算机的命令行运行 jar(因为我有一个适当的主类集)。但换一种说法,即使它在 IDE 中不起作用,它也应该在部署中起作用。

    【讨论】:

      猜你喜欢
      • 2020-11-17
      • 1970-01-01
      • 2022-01-22
      • 2016-03-29
      • 2013-10-13
      • 2022-09-26
      • 1970-01-01
      • 2022-10-07
      • 2011-01-14
      相关资源
      最近更新 更多