6. アノテーションの合成
既存のアノテーションを組み合わせて、容易にアノテーションを作成することができます。
この機能は、同じアノテーションの組み合わせを他の多くのフィールドに設定したくないときに利用します。
6.1. アノテーションの合成の基本
合成可能なアノテーションは決まっており、 書式の指定用 、 値の変換用 、 値の検証用 の3種のアノテーションです。
カラム指定用の @CsvColumn
などは合成できません。
@Target
として、ElementType.FIELD
とElementType.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}
もちろん、共通の属性 cases 、 message 、 groups も、アノテーション @CsvOverridesAttribute を使用して、特定のアノテーションの属性を上書きすることができます。
下記の例の場合、@CsvOverridesAttribute で上書きされていないアノテーションの属性 cases 、 message 、 groups は、共通の属性 cases 、 message 、 groups で上書きされます。
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}