メニュー > Webアプリケーション > Apache Struts > MessageResourcesをUTF-8で記述できるように改造する

MessageResourcesをUTF-8で記述できるように改造する

(2006/09/13)

動作環境

 このページでは以下の環境での動作を説明しています。
J2SDK 5.0 Update8
struts 1.2.8
Jakarta Commons Collection 3.2

native2asciiは面倒

 Java言語では設定ファイルや文字列リソースの保存ファイルとして*.propertiesファイルを用いるのが一般的です。Strutsでも類に漏れずMessageResourcesクラスからプロパティファイルにアクセスしています。
 しかし、このプロパティファイルには日本語を直接書き込めないという欠点があります。編集時にはJ2SDKに付属するnative2asciiを使って日本語を\udddd表記(Unicode)に変換したり戻したりといった作業を行わなければなりません。コマンド一発で変換可能とはいえ、プロパティファイルに何が書いてあるかを見るだけでも変換の必要があり面倒です。

ExtendedProperties

 何とかしてプロパティファイルに直接日本語を書き込めないでしょうか?ShiftJISでは問題がありそうですがUTF-8で記述するなら問題はないように思えます。
 そこでJakarta Commons Collectionsライブラリに用意されているExtendedPropertiesクラスを使うことにします。
 ExtendedPropertiesを用いると任意の文字コードで書かれたプロパティファイルを読み込むことができます。
ExtendedProperties properties = new ExtendedProperties();
properties.load(Messages.class.getResourceAsStream("/jp/co/mclnet/sample/resource/messages.properties"),
                "UTF-8");
return properties.getString(key);

MessageResourcesの改造

   新規にMessageResourcesのサブクラスを作成してUTF-8で書かれたプロパティファイルを読み込めるようにします。
 jp.co.mclnet.struts.util.MessageResourcesは抽象クラスです。Strutsではデフォルトでjp.co.mclnet.struts.util.PropertyMessageResourcesを使用しています。そこで、PropertyMessageResourcesを継承したExtendedPropertyMessageResourcesクラスを作成することにします。
 PropertyMessageResourcesとの違いは2カ所のみです。
public class ExtendedPropertyMessageResources extends PropertyMessageResources {
    /**
     * コンストラクタはスーパークラスのコンストラクタを呼び出すだけです。
     */
    public ExtendedPropertyMessageResources(MessageResourcesFactory factory,
                                            String config) {
        super(factory, config);
    }

    public ExtendedPropertyMessageResources(MessageResourcesFactory factory,
                                            String config,
                                            boolean returnNull) {
        super(factory, config, returnNull);
    }

    /*
     * loadLocaleメソッドでPropertiesの代わりにExtendedPropertiesを使用します。
     */
    protected synchronized void loadLocale(String localeKey) {

        if (log.isTraceEnabled()) {
            log.trace("loadLocale(" + localeKey + ")");
        }
        
        // Have we already attempted to load messages for this locale?
        if (locales.get(localeKey) != null) {
            return;
        }
        
        locales.put(localeKey, localeKey);

        // Set up to load the property resource for this locale key, if we can
        String name = config.replace('.', '/');
        if (localeKey.length() > 0) {
            name += "_" + localeKey;
        }
        
        name += ".properties";
        InputStream is = null;
        ExtendedProperties props = new ExtendedProperties();

        // Load the specified property resource
        if (log.isTraceEnabled()) {
            log.trace("  Loading resource '" + name + "'");
        }
        
        ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
        if (classLoader == null) {
            classLoader = this.getClass().getClassLoader();
        }
        
        is = classLoader.getResourceAsStream(name);
        if (is != null) {
            try {
                props.load(is, "UTF-8");
                
            } catch (IOException e) {
                log.error("loadLocale()", e);
            } finally {
                try {
                    is.close();
                } catch (IOException e) {
                    log.error("loadLocale()", e);
                }
            }
        }
        
        if (log.isTraceEnabled()) {
            log.trace("  Loading resource completed");
        }

        // Copy the corresponding values into our cache
        if (props.size() < 1) {
            return;
        }
        
        synchronized (messages) {
            Iterator names = props.keySet().iterator();
            while (names.hasNext()) {
                String key = (String) names.next();
                if (log.isTraceEnabled()) {
                    log.trace("  Saving message key '" + messageKey(localeKey, key));
                }
                messages.put(messageKey(localeKey, key), props.getProperty(key));
            }
        }
    }
}

 ExtendedPropertyMessageResourcesのインスタンスを生成するファクトリクラスも作ります。
public class ExtendedPropertyMessageResourcesFactory extends
                                                    MessageResourcesFactory {

    /*
     * ExtendedPropertyMessageResourcesのインスタンスを生成するだけです
     */
    public MessageResources createResources(String config) {
        return new ExtendedPropertyMessageResources(this,
                                                    config,
                                                    this.returnNull);
    }
}

 struts-config.xmlで、ExtendedPropertyMessageResourcesFactoryをファクトリクラスに指定します。
<message-resources factory="jp.co.mclnet.struts.util.ExtendedPropertyMessageResourcesFactory"
                     parameter="ApplicationResources"/>

 プロパティファイルにはUTF-8で記述してください。
message.hello=こんにちは世界

 今までのMessageResourcesと同様に<bean:message>タグなどから使えます。
<%@ taglib uri="http://jakarta.apache.org/struts/tags-bean"
           prefix="bean" %>



<bean:message key="message.hello"/>


Copyright (C)2005-2009 Miura Computer Limited. ALL RIGHTS RESERVED.