正方形の周長 #17

JDK1.6よりも前であれば面倒だったけれど、
1.6で導入されたResourceBundle.Controlクラスにより簡単に書くことができるようになった。
ResourceBundle.ControlクラスのAPI仕様にあるXMLベースのリソース取り込みのサンプルとあまり変わりない。

import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.IOException;
import java.net.URL;
import java.net.URLConnection;
import java.nio.charset.Charset;
import java.util.Arrays;
import java.util.List;
import java.util.Locale;
import java.util.PropertyResourceBundle;
import java.util.ResourceBundle;

public class PropertiesControl extends ResourceBundle.Control {
    private static final Charset UTF8 = Charset.forName("UTF-8");
    private Charset charset;

    public PropertiesControl() {
        this(UTF8);
    }

    public PropertiesControl(String charsetName) {
        this(Charset.forName(charsetName));
    }

    public PropertiesControl(Charset charset) {
        this.charset = charset;
    }

    private static final String FORMAT = "properties";
    private static final List<String> FORMATS = Arrays.asList(FORMAT);

    @Override
    public List<String> getFormats(String baseName) {
        if (baseName == null) throw new NullPointerException();
        return FORMATS;
    }

    @Override
    public ResourceBundle newBundle(String baseName, Locale locale, String format, ClassLoader loader, boolean reload) throws IOException {
        if (baseName == null || locale == null || format == null || loader == null) throw new NullPointerException();
        ResourceBundle bundle = null;
        if (format.equals(FORMAT)) {
            String bundleName = toBundleName(baseName, locale);
            String resourceName = toResourceName(bundleName, format);
            InputStream stream = null;
            if (reload) {
                URL url = loader.getResource(resourceName);
                if (url != null) {
                    URLConnection connection = url.openConnection();
                    if (connection != null) {
                        connection.setUseCaches(false);
                        stream = connection.getInputStream();
                    }
                }
            } else {
                stream = loader.getResourceAsStream(resourceName);
            }
            if (stream != null) {
                try (BufferedReader reader = new BufferedReader(new InputStreamReader(stream, charset))) {
                    bundle = new PropertyResourceBundle(reader);
                }
            }
        }
        return bundle;
    }
}

オーバーライドしたgetFormatsメソッドが返すListから分かるように、
プロパティファイルベースの取り込みにのみ対応しており、クラスベースのものは無視する。
newBundleメソッド内、PropertyResourceBundleでプロパティファイルを取り込む時に、
InputStreamでなく文字エンコードを指定したReaderを指定するのがポイントである。
ここではコンストラクタで任意のCharsetを指定できるようにはしているが、
UTF-8辺りが妥当なところだろうということで引数なしのときはUTF-8指定にしている。