JavaでWebアプリを作る場合、メッセージ類は普通は外部ファイルに定義する。
スタンダードなのはmessage.propertiesのような外部ファイルを作って、そこにkey-value形式でメッセージIDとメッセージを書いていく。 そしてResourceBundle クラスを使用して、プロパティファイルを読み取る。
public class PropertyUtil {
private static final String PROPERTY_PATH_MESSAGE = "messages";
public static String getMessage(String key, Object... args) {
ResourceBundle bundle = ResourceBundle.getBundle(PROPERTY_PATH_MESSAGE, locale);
return MessageFormat.format(bundle.getString(key), args);
}
}
messages_ja.properties
M0001={0}は必須です。
messages_en.properties
M0001={0} is required.
// テスト
String test = PropertyUtil.getMessage("M0001", "test");
定数や画面に表示する内容は簡単に変えられるように、外部にまとめて定義するというのは王道。それに外部ファイルに定義すればビルドをやり直さなくていい。
しかし実際問題、TomcatでJavaのWebアプリを本番環境で動かすという状況を考えると、これらの利点は失われると考えている。
まず、普通リリースするときはまとめてアプリをサーバにアップする。 本番環境のメッセージ用プロパティファイルを直接書き換える事態は早々起こらない。 バージョン管理システムへのコミット→検証環境での試験→本番環境という正規の手順を踏むべき。
次に、本番運用する場合は、Tomcatを再起動しない限りプロパティファイルを変更しても読み直さない設定にすることが普通なので、どうせ再起動するのであればビルド不要という利点も大したものではなくなる。
これらの利点が失われるのであれば、EnumとしてJavaのソースコードに組み込んだ方が、別の利点を取り込めていいのではないか?
プロパティファイルのデメリット | Enumで解消されるか? |
---|---|
メッセージIDが直書きなので、存在しないIDを書いてしまう。 定数クラスを作っても、直書きする人を防げない。 |
YES Enumは存在する値しか指定できない。 |
プロパティファイルとJavaの定義箇所と参照箇所のジャンプができない。 できたとしてもEclipseのプラグインが必要。 |
YES Eclipseのジャンプや呼び出し元の確認ができる。 |
日本語と英語の両方に同じメッセージがあることを保証できない。 日本語だけ追加/修正してしまう可能性がある。 |
YES) |
プロパティファイルのデメリットが全てEnumで解決できるし、Enumにすることでプロパティファイルより明らかに劣る部分もない。
コードは次のようなイメージ。
import java.text.MessageFormat;
public class PropertyUtil {
static AvailableLocal locale = AvailableLocal.JA;
public static String getMessage(Message message, Object... args) {
String pattern = message.getPattern(locale);
return MessageFormat.format(pattern, args);
}
// テスト
public static void main(String[] args) {
String test = getMessage(Message.M0001, "test");
System.out.println(test);
}
}
public enum Message {
M0001("{0}は必須です。"
, "{0} is required.")
,
;
private String messageJa;
private String messageEn;
private Message(String messageJa, String messageEn) {
this.messageJa = messageJa;
this.messageEn = messageEn;
}
public String getPattern(AvailableLocal locale) {
switch (locale) {
case JA: return messageJa;
case EN: return messageEn;
default: return messageJa;
}
}
}
import java.util.Locale;
public enum AvailableLocal {
JA(Locale.JAPAN)
, EN(Locale.ENGLISH)
,
;
private Locale locale;
private AvailableLocal(Locale locale) {
this.locale = locale;
}
public Locale get() {
return locale;
}
}