java-beginner.com ブログ

プログラミングを学習するブログ(Javaをメインに)

アノテーションの値順でフィールドを出力

投稿日:

最終更新日:2016年10月03日

アイキャッチ

こんにちは。「Javaを復習する初心者」です。

今回はアノテーションが付与されたフィールドをアノテーションに記述された値の順番で出力することをやりました。

自作する

アノテーションを次のように定義しました。フィールドに順序を定義するためのアノテーションです。

MyFieldOrder

@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface MyFieldOrder {
    int value();
}

アノテーションの定義自体にアノテーションを付与しています。「@Targe」はアノテーションを付与できる範囲を定義するときに使います。上記で使っている「ElementType.FIELD」の場合、アノテーションはフィールドのみに付与できます。「@Retention(RetentionPolicy.RUNTIME)」はリフレクションでアノテーションの情報を取得できるために必要です。

「int value();」と記述することにより、「@MyFieldOrder(value=1)」という具合にアノテーションを使うことができます。

フィールドに付与

TestDtoクラスを作り、次のようにアノテーションをフィールドに付与しました。

TestDto

public class TestDto {

    @MyFieldOrder(value=2)
    private String name;

    @MyFieldOrder(value=1)
    private String age;

    private String note;

    @Override
    public String toString() {
        return "TestDto [name=" + name + ", age=" + age + ", note=" + note + "]";
    }

}

3つのフィールドのうち、2つに「@MyFieldOrder」を付与しています。

以下、ソースと実行結果です。

ソース

        // フィールドを全て取得
        Field[] fields = TestDto.class.getDeclaredFields();
        System.out.println("全て取得");
        for (Field field : fields) {
            System.out.println(field.getName());
        }
        System.out.println("");

        // MyFieldOrderが付与されているフィールドのみ格納
        Set<Field> set = new TreeSet<>((o1, o2) -> {
            MyFieldOrder myFieldOrder1 = o1.getAnnotation(MyFieldOrder.class);
            MyFieldOrder myFieldOrder2 = o2.getAnnotation(MyFieldOrder.class);
            return myFieldOrder1.value() - myFieldOrder2.value();
        });
        for (Field field : fields) {
            if (field.getAnnotation(MyFieldOrder.class) != null) {
                set.add(field);
            }
        }
        System.out.println("MyFieldOrderの順番で出力");
        for (Field field : set) {
            System.out.println(field.getName());
        }
        System.out.println("");

        // 順序を考慮して格納
        String[] values = {"21", "name1"};
        TestDto dto = new TestDto();
        int index = 0;
        try {
            for (Field field : set) {
                field.setAccessible(true);
                field.set(dto, values[index++]);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        System.out.println(dto);

結果

全て取得
name
age
note

MyFieldOrderの順番で出力
age
name

TestDto [name=name1, age=21, note=null]

最初にフィールドすべてを取得しています。「TestDto.class.getDeclaredFields()」ではprivateフィールドも取得できます。

フィールドをアノテーションのvalue値の順番にするために、今回はTreeSetに格納することにしました。コンストラクタにComparatorの実装クラスを指定することで、順番を定義しています。[インスタンス].getAnnotation(MyFieldOrder.class)という記述で、@MyFieldOrderを取得できます。付与されていない場合、nullになり、のちの処理でエラーが発生するため、TreeSetに格納するFieldをアノテーションが付与されたものに限定しています。

最後に、具体例としてString配列の値を順番にフィールドに格納することをやっています。String配列は例えばCSVファイル等のデータだと仮定して、TestDtoのフィールドに格納するということをやっています。privateフィールドなのでsetAccessible(true)を記述しています。あとはsetメソッドで値を格納するだけです。出力結果「TestDto [name=name1, age=21, note=null]」でnameとageに値が格納されているのが確認できます。