繁体   English   中英

JarInputStream:getNextJarEntry始终返回null

[英]JarInputStream: getNextJarEntry always returns null

我有一个I18n帮助器类,可以通过查看应用程序Jar中文件的名称来找出可用的Locale

private static void addLocalesFromJar(List<Locale> locales) throws IOException {
    ProtectionDomain domain = I18n.class.getProtectionDomain();
    CodeSource src = domain.getCodeSource();
    URL url = src.getLocation();
    JarInputStream jar = new JarInputStream(url.openStream());
    while (true) {
        JarEntry entry = jar.getNextJarEntry();
        if (entry == null) {
            break;
        }
        String name = entry.getName();
        // ...
    }
}

目前,这不起作用 - jar.getNextJarEntry()似乎总是返回null 我不知道为什么会发生这种情况,我所知道的是url设置为rsrc:./ 我从未见过该协议,也找不到任何相关内容。

奇怪的是,这有效:

class Main {
    public static void main(String[] args) {
        URL url = Main.class.getProtectionDomain().getCodeSource().getLocation();
        JarInputStream jar = new JarInputStream(url.openStream());
        while (true) {
            JarEntry entry = jar.getNextJarEntry();
            if (entry == null) {
                break;
            }
            System.out.println(entry.getName());
        }
    }
}

在这个版本中,即使它们之间几乎没有区别, url也会正确设置为Jar文件的路径。

为什么第一个版本不起作用,是什么打破了它?

更新

工作示例实际上只有在我不使用Eclipse导出它时才有效。 它在NetBeans中运行得很好,但在Eclipse版本中,URL设置为rsrc:./

由于我将包含Package required libraries into generated JAR导出Package required libraries into generated JAR库处理中,因此Eclipse将其jarinjarloader放入我的Jar中,因此我可以在其中包含所有依赖项。 它可以与其他设置一起使用,但有没有办法使这个工作独立于它们?


另一个问题

目前,该类是我的应用程序的一部分,但我打算将它放在一个单独的库中。 在这种情况下,我如何确保它可以与单独的罐子一起使用?

问题是Eclipse正在使用的jarinjarloader ClassLoader。 显然它使用自己的自定义rsrc:URL方案指向存储在主jar文件中的jar文件。 您的URL流处理程序工厂无法理解此方案,因此openStream()方法返回null,这会导致您看到的问题。

这回答了关于单独罐子的问题的第二部分 - 不仅这将起作用,它是唯一可行的方式。 您需要更改主应用程序以使用单独的jar而不是将它们全部捆绑在主jar中。 如果您正在构建Web应用程序,请将它们复制到WEB-INF / lib目录中,您就可以了。 如果您正在构建桌面应用程序,请将META-INF / MANIFEST.MF中的相对路径引用添加到其他jar中,当您运行主jar时,它们将自动作为类路径的一部分包含在内。

代码可能会也可能不会导致I18n所在的jar文件。 getProtectionDomain也可以为null。 这取决于类加载器的实现方式。

ProtectionDomain domain = I18n.class.getProtectionDomain();
CodeSource src = domain.getCodeSource();
URL url = src.getLocation();

关于rsrc:./协议,类加载器可以随意使用他们喜欢的任何URL(或者为此命名)

试试这个,你可能会很幸运:)

URL url = getClass().getResource(getClass().getSimpleName()+".class");
java.net.JarURLConnection conn = (java.net.JarURLConnection) url.openConnection();
Enumeration<JarEntry> e = conn.getJarFile().entries();
...

还有祝你好运!

Eclipse的jarinjarloader使用系统类加载器加载所有内容,它永远不知道从哪个jar文件加载。 这就是为什么你不能获得rsrc: url的jar URL。

我建议将locales列表存储在每个应用程序jar的文件中,例如META-INF/locales 然后,您可以使用ClassLoader.getResources("META-INF/locales")获取类路径中具有该名称的所有文件的列表,并将它们组合以获取完整的语言环境列表。

我使用System.getProperty(“java.class.path”)来获取jar的位置。 我不知道这是否有所作为。 我没有探索过ProtectDomain路径,所以我无法帮助你,抱歉。 至于多个罐子,也只是遍历那些jar文件。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM