[英]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.