システム開発で思うところ

Javaで主にシステム開発をしながら思うところをツラツラを綴る。主に自分向けのメモ。EE関連の情報が少なく自分自身がそういう情報があったら良いなぁということで他の人の参考になれば幸い

FormへのBeanValidationにラベルをつける

はじめに

標準のBeanValidationで宣言的に実装する というのをするのは良いのですが、表示させるメッセージとしては「どの項目」というラベルが欲しいところです。

messageに項目名を付与した文言を都度指定する、というやり方もあると思いますが、テンプレートを使えるというメリットが無くなってしまいます。

使用側

FormでLabel指定(Formで検証不正)

定義側

@Label("Form Class Label")
public class LabelFormItem implements FormObject<String> {

(略)

}

結果

<<< FormValidationのメッセージにラベルが使用されます(FormObjecrt内指定) >>>
設定した値                               = 
検証時に変換されたメッセージ = {org.vermeerlab.validation.FormNotBlank.message}
遅延変換したメッセージ           = Form Class Labelは入力必須です。

FormでLabel指定(ValueObjectで検証不正)

定義側

FormでLabel指定(Formで検証不正) と同じ。

結果

<<< ValueValidationのメッセージにラベルが使用されます(FormObjecrt内指定) >>>
設定した値                               = 2
検証時に変換されたメッセージ = must be greater than or equal to 100
遅延変換したメッセージ           = Form Class Labelは100以上にしてください。

Formの使用側でLabelを指定(Formで検証不正)

定義側

@Data
public class LabelFormDirectLabel {

    @Valid
    @Label("Direct  Form Label")
    @FormNotBlank(groups = FormValidation.class)
    private LabelFormItem item;

}

結果

<<< FormValidationのメッセージにラベルが使用されます(直接指定) >>>
設定した値                               = 
検証時に変換されたメッセージ = {org.vermeerlab.validation.FormNotBlank.message}
遅延変換したメッセージ           = Direct  Form Labelは入力必須です。

LabelFormItemのクラスにもLabelを指定していますが、直接指定したものが優先されます。

Formの使用側でLabelを指定(ValueObjectで検証不正)

定義側

Formの使用側でLabelを指定(Formで検証不正) と同じ。

結果

<<< ValueValidationのメッセージにラベルが使用されます(直接指定) >>>
設定した値                               = 2
検証時に変換されたメッセージ = must be greater than or equal to 100
遅延変換したメッセージ           = Direct  Form Labelは100以上にしてください。

実装

Labelの読み込み

優先度は

Formで自分のラベルを持つ < Formの使用側でラベルを指定する

としました。

ざっくりいうと、外側で指定した情報を優先して上書きするというイメージです。

ポイントの抜粋

LabelAnnotationFilterでLabel情報を検証結果から取得しています。

List<String> pathes = Arrays.asList(constraintViolation.getPropertyPath().toString().split("\\."));

で検証でプロパティ名の数珠繋ぎを取得できるので、それをListにして再帰で順番に情報を取得しています。


Label classLabel = clazz.getAnnotation(Label.class);

でクラスに付与したLabelを取得

Field field = clazz.getDeclaredField(property);
Label fieldLabel = field.getAnnotation(Label.class);

でフィールドのLabelを取得

Label annotation = constraintViolation.getInvalidValue().getClass().getAnnotation(Label.class);

で検証不正の原因となったFormそのもののLabelを取得

Listで情報を保有せず、そのまま値を上書きしても良いところなのですが、階層を考慮したLabelの出力をしたいかもというボンヤリした構想もあったりしてListにしました。

Code

Bitbucket

さいごに

リフレクションを使ってどうにかして なんとかここまで という感じです。

リフレクションを使ったやり方は好ましくないのですが他に方法が思いつきませんでした。

しかも、これでラベルの問題は解決したかというと、そうでもないですね。

ラベル自体のプロパティ化をしておかないと結局のところ中途半端ですね。。

具体的には国際化対応のところで、直接入力した値(ここだと日本語)について、何かしら置き換えられる仕組みを設けておかないといけないと思っています。

あと、なんとなく、階層が複雑なバリエーションの場合、想定していないLabelを適用しそうな気もしています。

いずれにしても、まだBeanValidation関連で試してみたいことは残っているので、それらが一通り終わったら、改めてオレオレライブラリにするべく整理とテストをするつもりです。*1

*1:予定は未定ですが