メモの日々


2009年01月30日(金) [長年日記]

  • 中尾明慶が大江さんに似ていると思った。
  • 以前は新沼くんが中村憲剛に似ていると思っていたが今は似ていない。今は山下智久に似ていると思う。

[java] クラスパスからプロパティファイルを読み込む

クラスパス上にあるプロパティファイルを読み込む処理をたまに実装するが、すぐにやり方を忘れてしまうのでメモ。

基本的には、

とすればいい。このとき、getResourceAsStream() の引数に指定するリソース名の先頭には「/」を付与する。 クラスローダの構成が複雑な場合は気を付けることがあった気がするが、今は思い当たることがない。

Javaのドキュメントの次のページに説明がある。

以下にサンプルプログラムと実行例を示す。

(追記)

「getClass().getResourceAsStream("/test.properties")」と書いていたら、FindBugsに

this.getClass().getResource(...) の呼び出しは、別のパッケージに継承クラスがある場合には、予期しない結果をもたらす可能性があります。

と注意されてしまった。気にしなくていいケースもあるだろうが、重要なファイルを読み込む場合は注意が必要だ。対処方法のアドバイスは表示されなかったが、

  • クラスをfinalにし継承できないようにする
  • getClass()は使わず明示的にクラス名を指定する

などとする必要がありそう。以下のサンプルは後者の方法で修正した。

package sample;

import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.util.Map;
import java.util.Properties;

public class PropertiesLoader {
    public static void main(String[] args) throws IOException {
        PropertiesLoader loader = new PropertiesLoader();
        Properties props = loader.load();

        for (Map.Entry<Object, Object> entry : props.entrySet()) {
            System.out.printf("%s = %s%n", entry.getKey(), entry.getValue());
        }
    }

    public Properties load() throws IOException {
        //InputStream in = getClass().getResourceAsStream("/test.properties");
        InputStream in = PropertiesLoader.class.getResourceAsStream(
                "/test.properties");
        if (in == null) {
            throw new FileNotFoundException();
        }

        try {
            Properties props = new Properties();
            props.load(in);
            return props;
        } finally {
            in.close();
        }
    }
}
$ tree --noreport
.
|-- class
|   `-- sample
|       `-- PropertiesLoader.class
`-- etc
    `-- test.properties

$ cat etc/test.properties
name = oreore
lang = java
os = CentOS

$ java -cp class:etc sample.PropertiesLoader
name = oreore
os = CentOS
lang = java