6. アノテーションの合成

既存のアノテーションを組み合わせて、容易にアノテーションを作成することができます。

この機能は、同じアノテーションの組み合わせを他の多くのフィールドに設定したくないときに利用します。

6.1. アノテーションの合成の基本

合成可能なアノテーションは決まっており、 書式の指定用値の変換用値の検証用 の3種のアノテーションです。 カラム指定用の @CsvColumn などは合成できません。

  • @Target として、ElementType.FIELDElementType.ANNOTATION_TYPE の2つを指定します。

    • 通常はFieldのみで問題ないですが、 さらに合成するときがあるため、 ANNOTATION_TYPE も追加しておきます。

  • @Repeatable として、複数のアノテーションを設定できるようにします。

    • 内部クラスのアノテーションとして、 List を定義します。

  • 合成したのアノテーションと示すためのメタアノテーション @CsvComposition [ JavaDoc ]を指定します。

 1import java.lang.annotation.Annotation;
 2import java.lang.annotation.Documented;
 3import java.lang.annotation.ElementType;
 4import java.lang.annotation.Repeatable;
 5import java.lang.annotation.Retention;
 6import java.lang.annotation.RetentionPolicy;
 7import java.lang.annotation.Target;
 8
 9import com.github.mygreen.supercsv.annotation.CsvComposition;
10import com.github.mygreen.supercsv.annotation.constraint.*;
11import com.github.mygreen.supercsv.annotation.conversion.*;
12import com.github.mygreen.supercsv.annotation.format.*;
13
14
15// 合成したアノテーション
16@Target({ElementType.FIELD, ElementType.ANNOTATION_TYPE})
17@Retention(RetentionPolicy.RUNTIME)
18@Documented
19@Repeatable(CsvSalary.List.class)
20@CsvComposition                                      // 合成のアノテーションを表現するために指定します。
21@CsvNumberFormat(pattern="#,##0")                   // 書式の指定用のアノテーション
22@CsvDefaultValue(value="0", groups=ReadGroup.class)  // 値の変換用のアノテーション
23@CsvRequire                                          // 値の検証用のアノテーション(必須チェック)
24@CsvNumberRange(min="0", max="100,000,000" groups=NormalGroup.class)          // 値の検証用のアノテーション(範囲チェック)
25@CsvNumberRange(min="0", max="100,000,000,000", groups=ManagerGroup.class)    // 値の検証用のアノテーション(範囲チェック)
26public @interface CsvSalary {
27
28    // 繰り返しのアノテーションの格納用アノテーションの定義
29    @Target({ElementType.FIELD, ElementType.ANNOTATION_TYPE})
30    @Retention(RetentionPolicy.RUNTIME)
31    @Documented
32    @interface List {
33
34        CsvSalary[] value();
35    }
36}

使用する際には、他のアノテーションと同様にフィールドに付与します。

 1import com.github.mygreen.supercsv.annotation.CsvBean;
 2import com.github.mygreen.supercsv.annotation.CsvColumn;
 3
 4@CsvBean
 5public class SampleCsv {
 6
 7    @CsvColumn(number=1)
 8    @CsvSalary
 9    private Integer salary;
10
11    // getter/setterは省略
12}

6.2. 属性の上書き

合成したアノテーションに対して、一部の属性値を可変にしたい場合は、アノテーション @CsvOverridesAttribute [ JavaDoc ]を使用します。

  • 属性 annotation で上書き対象のアノテーションを指定し、属性 name で属性名を指定します。

  • アノテーション @CsvOverridesAttribute を複数付与することで、1つの属性で複数の属性を上書きすることができます。

 1import java.lang.annotation.Annotation;
 2import java.lang.annotation.Documented;
 3import java.lang.annotation.ElementType;
 4import java.lang.annotation.Repeatable;
 5import java.lang.annotation.Retention;
 6import java.lang.annotation.RetentionPolicy;
 7import java.lang.annotation.Target;
 8
 9import com.github.mygreen.supercsv.annotation.CsvComposition;
10import com.github.mygreen.supercsv.annotation.CsvOverridesAttribute;
11import com.github.mygreen.supercsv.annotation.constraint.*;
12import com.github.mygreen.supercsv.annotation.conversion.*;
13import com.github.mygreen.supercsv.annotation.format.*;
14
15
16@Target({ElementType.FIELD, ElementType.ANNOTATION_TYPE})
17@Retention(RetentionPolicy.RUNTIME)
18@Documented
19@Repeatable(CsvSalary.List.class)
20@CsvComposition
21@CsvNumberFormat(pattern="#,##0")
22@CsvDefaultValue(value="0", groups=ReadGroup.class)  // 上書き対象のアノテーション
23@CsvRequire                                          // 上書き対象のアノテーション
24@CsvNumberRange(min="0", max="100,000,000", groups=NormalGroup.class)
25@CsvNumberRange(min="0", max="100,000,000,000", groups=ManagerGroup.class)
26public @interface CsvSalary {
27
28    // @CsvDefaultValueの属性valueの上書き
29    @CsvOverridesAttribute(annotation=CsvDefaultValue.class, name="value")
30    String defaultValueRead();
31
32    // @CsvRequireの属性considerBlankとconsiderEmptyの上書き
33    @CsvOverridesAttribute(annotation=CsvRequire.class, name="considerBlank")
34    @CsvOverridesAttribute(annotation=CsvRequire.class, name="considerEmpty")
35    boolean considerSpace() default true;
36
37    @Target({ElementType.FIELD, ElementType.ANNOTATION_TYPE})
38    @Retention(RetentionPolicy.RUNTIME)
39    @Documented
40    @interface List {
41
42        CsvSalary[] value();
43    }
44}

上書き対象のアノテーション自体が複数付与されている場合、区別するために @CsvOverridesAttribute(index=<インデックス>) で指定します。

  • 属性 index は0から始まります。

  • インデックスを指定しない場合は、該当するアノテーションの属性が全て上書きされます。

 1import java.lang.annotation.Annotation;
 2import java.lang.annotation.Documented;
 3import java.lang.annotation.ElementType;
 4import java.lang.annotation.Repeatable;
 5import java.lang.annotation.Retention;
 6import java.lang.annotation.RetentionPolicy;
 7import java.lang.annotation.Target;
 8
 9import com.github.mygreen.supercsv.annotation.CsvComposition;
10import com.github.mygreen.supercsv.annotation.CsvOverridesAttribute;
11import com.github.mygreen.supercsv.annotation.constraint.*;
12import com.github.mygreen.supercsv.annotation.conversion.*;
13import com.github.mygreen.supercsv.annotation.format.*;
14
15
16@Target({ElementType.FIELD, ElementType.ANNOTATION_TYPE})
17@Retention(RetentionPolicy.RUNTIME)
18@Documented
19@Repeatable(CsvSalary.List.class)
20@CsvComposition
21@CsvNumberFormat(pattern="#,##0")
22@CsvDefaultValue(value="0", groups=ReadGroup.class)
23@CsvRequire
24@CsvNumberRange(min="0", max="100,000,000", groups=NormalGroup.class)       // 1番目(index=0)のアノテーション
25@CsvNumberRange(min="0", max="100,000,000,000", groups=ManagerGroup.class) // 2番目(index=1)のアノテーション
26public @interface CsvSalary {
27
28    // 2番目(インデックスが1)の@CsvNumberRangeの属性maxの上書き
29    @CsvOverridesAttribute(annotation=CsvNumberRange.class, name="max", index=1)
30    String managerSalaryMax() default "100,000,000,000,000";
31
32    @Target({ElementType.FIELD, ElementType.ANNOTATION_TYPE})
33    @Retention(RetentionPolicy.RUNTIME)
34    @Documented
35    @interface List {
36
37        CsvSalary[] value();
38    }
39}

6.3. 共通の属性の上書き

共通の属性である cases, groups , message は、アノテーション @CsvOverridesAttribute が無くても上書きすることができます。

 1import java.lang.annotation.Annotation;
 2import java.lang.annotation.Documented;
 3import java.lang.annotation.ElementType;
 4import java.lang.annotation.Repeatable;
 5import java.lang.annotation.Retention;
 6import java.lang.annotation.RetentionPolicy;
 7import java.lang.annotation.Target;
 8
 9import com.github.mygreen.supercsv.annotation.CsvComposition;
10import com.github.mygreen.supercsv.annotation.CsvOverridesAttribute;
11import com.github.mygreen.supercsv.annotation.constraint.*;
12import com.github.mygreen.supercsv.annotation.conversion.*;
13import com.github.mygreen.supercsv.annotation.format.*;
14import com.github.mygreen.supercsv.builder.BuildCase;
15
16
17@Target({ElementType.FIELD, ElementType.ANNOTATION_TYPE})
18@Retention(RetentionPolicy.RUNTIME)
19@Documented
20@Repeatable(CsvSalary.List.class)
21@CsvComposition
22@CsvNumberFormat(pattern="#,##0")                                           // 共通の属性messageを持つ
23@CsvDefaultValue(value="0", groups=ReadGroup.class)                          // 共通の属性groupsを持つ
24@CsvRequire                                                                  // 共通の属性message, groupsを持つ
25@CsvNumberRange(min="0", max="100,000,000", groups=NormalGroup.class)         // 共通の属性message, groupsを持つ
26@CsvNumberRange(min="0", max="100,000,000,000", groups=ManagerGroup.class)   // 共通の属性message, groupsを持つ
27public @interface CsvSalary {
28
29    // 共通の属性 - エラーメッセージ
30    String message() default "";
31
32    // 共通の属性 - ケース
33    BuildCase[] cases() default {};
34
35    // 共通の属性 - グループ
36    Class<?>[] groups() default {};
37
38    @Target({ElementType.FIELD, ElementType.ANNOTATION_TYPE})
39    @Retention(RetentionPolicy.RUNTIME)
40    @Documented
41    @interface List {
42
43        CsvSalary[] value();
44    }
45}

もちろん、共通の属性 casesmessagegroups も、アノテーション @CsvOverridesAttribute を使用して、特定のアノテーションの属性を上書きすることができます。

下記の例の場合、@CsvOverridesAttribute で上書きされていないアノテーションの属性 casesmessagegroups は、共通の属性 casesmessagegroups で上書きされます。

 1import java.lang.annotation.Annotation;
 2import java.lang.annotation.Documented;
 3import java.lang.annotation.ElementType;
 4import java.lang.annotation.Repeatable;
 5import java.lang.annotation.Retention;
 6import java.lang.annotation.RetentionPolicy;
 7import java.lang.annotation.Target;
 8
 9import com.github.mygreen.supercsv.annotation.CsvComposition;
10import com.github.mygreen.supercsv.annotation.CsvOverridesAttribute;
11import com.github.mygreen.supercsv.annotation.constraint.*;
12import com.github.mygreen.supercsv.annotation.conversion.*;
13import com.github.mygreen.supercsv.annotation.format.*;
14
15
16@Target({ElementType.FIELD, ElementType.ANNOTATION_TYPE})
17@Retention(RetentionPolicy.RUNTIME)
18@Documented
19@Repeatable(CsvSalary.List.class)
20@CsvComposition
21@CsvNumberFormat(pattern="#,##0")                                            // 共通の属性messageを持つ
22@CsvDefaultValue(value="0", groups=ReadGroup.class)                          // 共通の属性cases, groupsを持つ
23@CsvRequire                                                                  // 共通の属性cases, message, groupsを持つ
24@CsvNumberRange(min="0", max="100,000,000", groups=NormalGroup.class)        // 共通の属性cases, message, groupsを持つ
25@CsvNumberRange(min="0", max="100,000,000,000", groups=ManagerGroup.class)   // 共通の属性cases, message, groupsを持つ
26public @interface CsvSalary {
27
28    // 共通の属性 - エラーメッセージ
29    String message() default "";
30
31    // 2番目(index=1)の@CsvNumberRangeの属性messageの上書き
32    @CsvOverridesAttribute(annotation=CsvNumberRange.class, name="message", index=1)
33    String rangeMessage() default "管理者の場合の給料は、{min}~{max}の範囲内で設定してください。";
34
35    // 共通の属性 - ケース
36    BuildCase[] cases() default {};
37
38    // 1番目(index=0)の@CsvNumberRangeの属性casesの上書き
39    @CsvOverridesAttribute(annotation=CsvNumberRange.class, name="cases", index=0)
40    BuildCases[] normalRangeCases() default {};
41
42    // 共通の属性 - グループ
43    Class<?>[] groups() default {};
44
45    // 1番目(index=0)の@CsvNumberRangeの属性groupsの上書き
46    @CsvOverridesAttribute(annotation=CsvNumberRange.class, name="groups", index=0)
47    Class<?>[] normalRangeGroups() default {};
48
49    @Target({ElementType.FIELD, ElementType.ANNOTATION_TYPE})
50    @Retention(RetentionPolicy.RUNTIME)
51    @Documented
52    @interface List {
53
54        CsvSalary[] value();
55    }
56}