JarInputStream:getNextJarEntry始终返回null

时间:2011-03-05 20:35:57

标签: java jar

我有一个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库处理导出它,Eclipse将其jarinjarloader放入我的Jar中,因此我可以在其中包含所有依赖项。它可以与其他设置一起使用,但有没有办法让它独立于它们工作?


另一个问题

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

4 个答案:

答案 0 :(得分:2)

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

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

答案 1 :(得分:1)

代码可能会也可能不会导致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();
...

祝你好运!

答案 2 :(得分:1)

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

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

答案 3 :(得分:0)

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