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

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

Labelが無くても良いようにしてみた

vermeer.hatenablog.jp

の続きです。

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

Bitbucket

さいごに

今回はコード貼り付けだけという感じですが、イイ感じ(?)に混沌としてきました。

とりあえず、やりたいことは盛り込めているように思います。

ただ、こういうEasyに向けた仕組みは黒魔術になるんですよね。

そうなると、ルールをドキュメントにするのも大事だけれど、規約以外で(FindBugsみたいな感じで)順守できるような仕組みも同時に作りこまないと陳腐化しそうなんですよね。

これは、また別で考えよう。