DeltaSpikeのI18nタイプセーフメッセージを試してみる

DeltaSpikeのドキュメントを見ているとI18nという章があり、タイプセーフメッセージについて記載されていますが、今回はこれを少し試したいと思います。

DeltaSpikeではメッセージを扱うインターフェースを定義し、特定のメッセージを取得するメソッドをインターフェースに定義し、適切なアノテーションを付与することでメッセージの取得を行うことができるようです。文章で説明してもよくわからないと思うので、ドキュメントにある最も簡単なメッセージ出力例を少しアレンジしたもので紹介します。

@MessageBundle
public interface HogeMessage {

    @MessageTemplate("hoge hoge")
    public String hogeHoge();
}

@MessageBundleはおまじないのようなものだと思ってください。ここで重要なのは必要なのはインターフェースのみで実装は必要ありません。メッセージを取得する側に当該メッセージバンドルインターフェースをDIし、hogeHogeというメソッドを呼び出すと@MessageTemplateで定義したメッセージ(hoge hoge)が取得できます。

実際メッセージは*.propertiesファイルに定義し読み込むことが一般的だと思いますが、DeltaSpikeでこれを行うにはまず@MessageBundleを付与したクラスと同名のプロパティファイルを同じパッケージ階層に作成します。

例えばHogeMessage.java(.class)のパッケージがorg.example.msgならばHogeMessage.propertiesファイルもorg.example.msgパッケージ配下に配置します。メッセージファイルに以下のようなメッセージが存在する場合、


hello_hoge=Hello hoge!!

当該メッセージを取得するためのメソッドに付与する@MessageTemplateにはキー名を"{"、"}"で囲った値を定義します。

@MessageTemplate("{hello_hoge}")

では、もう一歩進んでメッセージファイルのメッセージにプレースホルダを定義し、任意の値をバインドするにはどうするかというと、これはデフォルトではできないようです。DeltaSpikeにDefaultMessageInterpolatorというクラスがありますが、このクラスは受け取ったメッセージテキストをただ返却しているだけです。標準で{0}とかにバインドしてくれてもいいような気もしますが、泣き言いっても無いものは無いのでMessageInterpolatorインターフェースを実装して自分で組み込むしかないようです。

【MessageInterpolatorインターフェース実装例】

import org.apache.deltaspike.core.api.message.MessageInterpolator;

public class MyMessageInterpolator implements MessageInterpolator {

    @Override
    public String interpolate(String messageText, Object[] arguments) {
        final MessageFormat format = new MessageFormat(messageText);
        return format.format(arguments);
    }

}

メッセージファイルには次のようなメッセージを作成します。


hello=Hello {0} !

自作したMessageInterpolatorを利用するにはどうするかというと@MessageContextConfigアノテーションでMessageInterpolatorクラスを定義するだけです。

@MessageBundle
@MessageContextConfig(messageInterpolator = MyMessageInterpolator.class)
public interface ApplicationMessage {

    @MessageTemplate("{hello}")
    public String sayHello(String name);
}

ここで、sayHelloというメソッドの引数にnameを設定しています。ApplicationMessage#sayHelloメソッド呼び出し側でsayHelloメソッドのnameに設定された値がメッセージファイルのプレースホルダ{0]にバインドされる訳です。

【呼び出し側】

@Inject
private ApplicationMessage applicationMessage;

...
public void hello() {
    String message = applicationMessage.sayHello("hoge");
}

なお、@MessageContextConfigではMessageInterpolator以外に、MessageResolverとLocaleResolverも独自クラスを組み込めるようになっています。

この辺は時間がありなおかつ気が向いたら紹介したいと思います。