Java Web Startとリソースとクラスローダ(その2)
AppClassLoaderはローカル環境で使われるので、リソースパスにFileクラスを使って検索している。一方でJNLPClassLoaderはリソースパスにURLクラスを使うので拡張子もパスの一部。だからケースセンシティブなのか?
実際にアプリケーションを起動して、AppClassLoaderがリソースを見つける直前のスタックトレースを見てみた。
Thread [main] (Suspended) URLClassPath$FileLoader.findResource(String, boolean) line: 961 URLClassPath.findResource(String, boolean) line: 145 URLClassLoader$2.run() line: 362 [local variables unavailable] AccessController.doPrivileged(PrivilegedAction, AccessControlContext) line: not available [native method] Launcher$AppClassLoader(URLClassLoader).findResource(String) line: 359 Launcher$AppClassLoader(ClassLoader).getResource(String) line: 977 :
AppClassLoaderの継承元クラスはURLClassLoaderだが、実際にクラスを含むリソースをロードするために、内部ではURLClassPathというクラスを利用しており、それぞれロードするリソースの種類により
URLClassPath$Loader (URLからリソースをロードするためのローダと思われる) URLClassPath$FileLoader (ローカルのファイルシステムからロードするためのローダと思われる) URLClassPath$JarFileLoader (jarアーカイブの、、、以下略)
これらの3つに委譲されるぽい。(rt.jar中のクラス名から)
sun.miscパッケージのリバースエンジニアリングが許可されているかの確認を取っていないので確証は取れていないが、URLClassPath$FileLoaderはその名前から推測するに、内部ではパスを実パスに変換した上で、java.io.Fileクラスを使ってリソースをロードしているので拡張子はignore caseなのではないだろうか。
一方、以下がJava Web Start経由で起動した場合にリソースを取得する直前のスタックトレースだ。
System Thread [javawsApplicationMain] (Suspended) URLClassPath$JarLoader.getResource(String, boolean) line: not available URLClassPath$JarLoader.findResource(String, boolean) line: not available URLClassPath.findResource(String, boolean) line: not available URLClassLoader$2.run() line: not available AccessController.doPrivileged(PrivilegedAction, AccessControlContext) line: not available [native method] JNLPClassLoader(URLClassLoader).findResource(String) line: not available JNLPClassLoader.findResource(String) line: 268 JNLPClassLoader(ClassLoader).getResource(String) line: not available : :
同様にURLClassPathクラスが使われているが、今度は$JarLoaderがローダとして使われている。
JNLPはURLを使ってJarファイル及び内部のリソースファイルをロードするので、この場合全てのパスはパッケージがマップされたURLとして扱われる、よってcase sensitiveなのではないかと。
追記 : JNLPClassLoaderはJava6で書き換えられたらしい