カスタム Bean Validation の initialize でアノテーションのパラメータをインスタンス変数に保持して大丈夫なのか

一応、調べてみます。ドキュメントはこちら。
http://docs.oracle.com/javaee/7/api/javax/validation/ConstraintValidator.html

This method can be accessed concurrently, thread-safety must be ensured by the implementation.

バリデータのインスタンスは同一のものが使い回されるようです。そのため、isValid はスレッドセーフに実装する必要があります。

で、アノテーションのパラメータを initialize の中でインスタンス変数に保持するコードは割と一般的ですが、アノテーションのパラメータに異なる値を渡して検証する場合、isValid の処理で不整合が発生しないんだろうか、ということを調べてみます。

こんなアノテーションを用意。param でパラメータを取れるようにしておきます。

gist.github.com

こんなバリデータを用意。initializeアノテーションのパラメータをインスタンス変数に保持して、isValid で利用することを想定します。バリデーションロジックは適当です。

gist.github.com

こんなテストコードを用意。Bean のフィールドに指定している @SampleValidation には同じパラメータを渡します。

gist.github.com

これを実行すると以下のように出力されます。同一のインスタンスが使われています。

@initialize : param=hoge, hashCode=1858609436
@isValid : param=hoge, hashCode=1858609436, value=bar
@isValid : param=hoge, hashCode=1858609436, value=foo

次に、Bean のフィールドに指定しているアノテーションに別々のパラメータを渡します。

@SampleValidation(param = "hoge")
private String name;
@SampleValidation(param = "fuga")
private String value;

で、先ほどのテストコードを実行すると以下のように出力されます。アノテーションごとに別々のインスタンスが使われるようになります。

@initialize : param=fuga, hashCode=1858609436
@isValid : param=fuga, hashCode=1858609436, value=bar
@initialize : param=hoge, hashCode=786041152
@isValid : param=hoge, hashCode=786041152, value=foo
まとめ

アノテーションに別々のパラメータを渡すと、バリデータはアノテーションごとに別々のインスタンスが使われる。なるほど。