JAR索引和getResources

时间:2016-02-23 23:49:52

标签: java indexing jar resources classloader

在我看来,JAR file indexing打破了ClassLoader.getResources()的机制。请考虑以下程序:

import java.io.*;
import java.net.*;
import java.util.*;

public class TryIt {
    public static void main(String[] args) throws Exception {
        URL[] urls = {
            (new File("a.jar")).getAbsoluteFile().toURI().toURL(),
            (new File("b.jar")).getAbsoluteFile().toURI().toURL()
        };
        URLClassLoader cl = URLClassLoader.newInstance(urls);
        String[] res = { "foo", "foo/", "foo/arb", "foo/bar", "foo/cab" };
        for (String r: res) {
            System.out.println("'" + r + "':");
            for (URL u: Collections.list(cl.getResources(r)))
                System.out.println(" " + u);
        }
    }
}

现在准备该程序中提到的JAR文件:

mkdir a/foo b/foo
touch a/foo/arb a/foo/bar b/foo/bar b/foo/cab
echo "Class-Path: b.jar" > mf
jar cfm a.jar mf -C a foo
jar cf b.jar -C b foo

如果您运行java TryIt,您将获得如下输出:

'foo':
 jar:file:…/a.jar!/foo
 jar:file:…/b.jar!/foo
'foo/':
 jar:file:…/a.jar!/foo/
 jar:file:…/b.jar!/foo/
'foo/arb':
 jar:file:…/a.jar!/foo/arb
'foo/bar':
 jar:file:…/a.jar!/foo/bar
 jar:file:…/b.jar!/foo/bar
'foo/cab':
 jar:file:…/b.jar!/foo/cab

但是如果你运行jar -i a.jar来创建一个索引,那么上面的命令就会打印出来:

'foo':
 jar:file:…/a.jar!/foo
'foo/':
 jar:file:…/a.jar!/foo/
'foo/arb':
 jar:file:…/a.jar!/foo/arb
'foo/bar':
 jar:file:…/a.jar!/foo/bar
'foo/cab':
 jar:file:…/b.jar!/foo/cab

索引本身如下:

JarIndex-Version: 1.0

a.jar
foo

b.jar
foo

getResources的合同是否意味着应该返回与给定名称匹配的所有可用资源?

  

查找具有给定名称的所有资源。

the JAR File Specification不允许索引包跨越多个JAR文件吗?

  

通常一个包名称映射到一个jar文件,但如果一个特定的包跨越多个jar文件,那么该包的映射值将是一个jar文件列表。

是否有某些规范表明我所观察到的确实是正确的(或至少是允许的)行为?

是否有一些解决方法可以获得所有命名资源,尽管有索引?

1 个答案:

答案 0 :(得分:2)

这似乎是一个错误。
我已经向Oracle报告了它,它现在在他们的bug数据库中为bug 8150615

我在OpenJDK源代码中进行了一些挖掘,并在那里找到了这种行为的共鸣。

此处的相关课程为sun.misc.URLClassPath。它包含一个(懒惰构造的)list of loadersqueries each loader in turn来组合其结果。但是,如果是JAR文件contains an index,则其中的JAR文件将explicitely be excluded from getting added添加到加载程序列表中。相反,包含索引的JAR的加载器将query said index用于相关名称,traversed the resulting list。但是这里有一个问题:这发生在方法URLClassPath$JarLoader.getResource中,该方法返回单个 Resource对象。此方法无法返回多个资源。由于索引中的所有对象都由单个加载器处理,因此我们只能得到一个资源。