失敗は一時の恥

パッケージソフト開発をしているプログラマが気の赴くままに何かを投稿するブログ.

Jar に含まれるリソースを検索する

概要

Java のコードから Jar に含まれるリソースファイルを取得する場合は,おそらく最も単純な方法だと ClassLoader#getResource(String) メソッドなどを使うことになると思います.

ですが,「指定した名前のリソースを取得」するというよりも,「名前が特定のパターンのリソースをすべて取得」したいといった状況もあるのではないでしょうか.

そのようなことはどうすればいいのか調べていたところ

といった解決策を見つけることができました.

Corn CPS

Corn Classpath Scanner (略して CPS) は,その名の通りクラスパスの探索を行うためのライブラリです.

使ってみる

pom.xml に Corn CPS を追加します:

<dependency>
  <groupId>net.sf.corn</groupId>
  <artifactId>corn-cps</artifactId>
  <version>1.1.10</version>
</dependency>

例えば "default_*.png" といったパターンの名前を持つリソースを見つけるには,次のようにします.

List<URL> urls = CPScanner.scanResources(new ResourceFilter().resourceName("default_*.png"));

ちなみに,これで返ってくる URL は jar:file:/... といった値になっています. こういった URL にアクセスするために,Java には JarURLConnection というクラスが用意されているということに初めて気がつきました.
(普段 ClassLoader#getResourceAsStream(String) でストリームを直接取っていた)

PathMatchingResourcePatternResolver

こちらは Spring Framework に含まれているクラスです.

すでに Spring を使っている環境ではこちらの方が導入の手間がなくて済むのかもしれません.
(逆に,リソースの検索のためだけに Spring のライブラリを入れるというのもどうかと思います)

使ってみる

pom.xml にライブラリを追加します:

<dependency>
  <groupId>org.springframework</groupId>
  <artifactId>spring-core</artifactId>
  <version>5.1.4.RELEASE</version>
</dependency>

先ほどの例のように "default_*.png" といったパターンの名前を持つリソースを見つけるには,次のようにします.

PathMatchingResourcePatternResolver resolver = new PathMatchingResourcePatternResolver();
Resource[] resources = resolver.getResources("classpath*:/**/default_*.png");

ここで返ってくるのは org.springframework.core.io.Resource 型の値です.

リソースの内容は Resource#getInputStream() メソッドなどを使えば読み出すことができます.

リソース検索の仕組み

これらのライブラリの中身はどのようなことをしているのだろう?と思って,CPScanner のソースを見てみました. 見てみましたが,僕にはパッと見では何故これで求めているリソースが取得できるのか理解できませんでした……

おわり

Jar の中から特定パターンの名前を持つリソースを検索するライブラリとして Corn CPS と PathMatchingResourcePatternResolver を紹介しました. 便利なライブラリがあったものですが,使うだけでなく余裕があるときに中身も読んで理解していきたいものです.