2016-02-23 20 views
3

在我看來,JAR file indexing打破了ClassLoader.getResources()的機制。考慮下面的程序:JAR索引和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

這似乎是一個錯誤。
我已經報告給Oracle,現在它的bug數據庫爲bug 8150615


我在OpenJDK資源中做了一些挖掘工作,發現了這種行爲的共鳴。

這裏的相關課是sun.misc.URLClassPath。它包含一個(懶散地構建的)list of loadersqueries each loader in turn來組裝它的結果。但是,如果一個JAR文件contains an index,那麼其中的JAR文件將explicitely be excludedfrom getting added加載到列表中。相反,包含索引的JAR的加載程序將爲query said index作爲問題名稱,而traversed the resulting list。但這裏有一個問題:這發生在一個方法URLClassPath$JarLoader.getResource,它返回一個單一的Resource對象。這種方法不可能返回多個資源。由於索引中的所有對象都由一個加載器來處理,所以我們只能獲得一個資源。