从main()方法中获取可执行jar文件的名称

40

我创建了一个可执行的jar包,并使用commons-cli来让用户在启动客户端时指定命令行参数。一切都正常。但是,当我打印出该jar包的用法说明时,我希望显示以下内容:

usage: java -jar myprog.jar <options> <file>
--help Display the help message
--debug Enable debugging
....

使用commons-cli可以轻松地打印出所有选项。然而,“usage”行是让人伤透脑筋的。我似乎找不到获取传递给应用程序的args[]中“myprog.jar”名称的方法。

有没有什么简单的方法可以做到这一点?我可以使用相当复杂的方法从我的类加载器的类中回溯,并确定它是否包含在一个jar文件中,但这似乎是对应该是一个相当简单的问题的一个相当丑陋的答案。

private String getPath(Class cls) {
    String cn = cls.getName();
    String rn = cn.replace('.', '/') + ".class";
    String path =
            getClass().getClassLoader().getResource(rn).getPath();
    int ix = path.indexOf("!");
    if(ix >= 0) {
        return path.substring(0, ix);
    } else {
        return path;
    }
}

尝试过访问 https://dev59.com/enRC5IYBdhLWcg3wXPwC?lq=1 吗? - Charles
我已经看到了那个链接,但它似乎也是一种“hack”的方式。我无法相信没有更直接的解决方案。此外,API指出“getCodeSource()”可能返回null,但没有详细说明在哪些条件下会发生这种情况,因此我自然想知道这是否是一种“故障安全”方法可供使用。 - Eric B.
2个回答

62

给你:

new java.io.File(SomeClassInYourJar.class.getProtectionDomain()
  .getCodeSource()
  .getLocation()
  .getPath())
.getName()

编辑:我看到你有关 getSourceCode API 的评论。好吧,在 Java 中,这可能是你能做的最好的事情了。关于 getCodeSource() 返回 null,我认为这主要发生在 java.lang.* 类和其他源位置“隐藏”的特殊类中。不过,对于你自己的类应该可以正常工作。


1
谢谢 - 这正是@Charles在SO链接中指出的相同问题。正如我上面提到的,我最担心的是getCodeSource()的API表明它可能为空,但没有详细说明在哪些情况下会为空。 - Eric B.
另一个问题是它没有考虑到类文件可能嵌套在存档文件中的事实。因此,我仍然需要检查子字符串。就像我说的那样,这似乎有点笨拙,我很惊讶Java没有更好的解决方案。 - Eric B.
这主要是因为很少有理由知道你正在运行的jar文件的名称。功能应该(理想情况下)独立于名称。 - Charles
@rodion 对我来说,以上代码输出的是“classes!” - saravana kumar ramasamy
你知道这种技术是否适用于GraalVM AOTC吗?我想创建一个多调用二进制文件。 - Sridhar Sarnobat

2

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