の続きです。
AnnotationでLabelを付与するという仕組みにしたわけですが、よくよく考えてみるとFormObject
というインターフェースをもっているのだから、そこで対象クラスを判断してProperty
に登録した表示項目名を参照するようにしても良いのでは?と思いました。
もちろん、Labelは残しておきますが、そういうのもアリかな?ということです。
ということで試しにやってみました。
方式
FormObject
インターフェースを実装したクラスについては「変換する対象となるラベル情報」をResourceBundleから取得する。独自の表示項目名を指定したい場合は
@Label
を使う。
実装
Interfaceを処理対象に
フォームクラスのインターフェースの確認およびキー値を編集
public class LabelConverter { private final ConstraintViolation<?> constraintViolation; private final List<String> pathes; private final List<String> labels; private int deepIndex; private LabelConverter(ConstraintViolation<?> constraintViolation, List<String> paths) { this.constraintViolation = constraintViolation; this.pathes = paths; this.labels = new ArrayList<>(); this.deepIndex = 0; } public static LabelConverter of(ConstraintViolation<?> constraintViolation) { List<String> pathes = Arrays.asList(constraintViolation.getPropertyPath().toString().split("\\.")); return new LabelConverter(constraintViolation, pathes); } public String filter() { Class<?> clazz = this.constraintViolation.getRootBeanClass(); this.recursiveFilter(clazz, this.pathes.get(deepIndex)); Class<?> invalidClazz = constraintViolation.getInvalidValue().getClass(); Label annotation = invalidClazz.getAnnotation(Label.class); if (annotation != null) { this.labels.add(annotation.value()); } //インターフェースからキー値を編集 if (FormObject.class.isAssignableFrom(invalidClazz)) { this.labels.add(invalidClazz.getCanonicalName() + ".label"); } String _label = this.labels.isEmpty() ? "" : this.labels.get(0); return _label; } void recursiveFilter(Class<?> clazz, String property) { try { Label classLabel = clazz.getAnnotation(Label.class); if (classLabel != null) { this.labels.add(classLabel.value()); } //インターフェースからキー値を編集 if (FormObject.class.isAssignableFrom(clazz)) { this.labels.add(clazz.getCanonicalName() + ".label"); } Field field = clazz.getDeclaredField(property); Label fieldLabel = field.getAnnotation(Label.class); if (fieldLabel != null) { this.labels.add(fieldLabel.value()); } Class<?> nextClass = clazz.getDeclaredField(property).getType(); if (deepIndex < this.pathes.size() - 1) { deepIndex++; this.recursiveFilter(nextClass, this.pathes.get(deepIndex)); } } catch (NoSuchFieldException | SecurityException ex) { } } }
Propertyファイル
参照する
Property
は専用のものを準備キー値は「クラスパス」+「label」として衝突を避ける
キー値は「Label」で指定したプロパティーキー
というようなルールを設けました。
org.vermeerlab.targets.form.nolabel.FormItemNoLabel.label = 【Formクラスには設定がない】 FormWithPropertyKey.label = 【直接指定のプロパティキー】 FormItemWithPropertyKey.label = 【Form指定のプロパティキー】
実行結果
(略)
Code
さいごに
今回はコード貼り付けだけという感じですが、イイ感じ(?)に混沌としてきました。
とりあえず、やりたいことは盛り込めているように思います。
ただ、こういうEasyに向けた仕組みは黒魔術になるんですよね。
そうなると、ルールをドキュメントにするのも大事だけれど、規約以外で(FindBugsみたいな感じで)順守できるような仕組みも同時に作りこまないと陳腐化しそうなんですよね。
これは、また別で考えよう。