独自の変換処理の作成方法
独自の変換処理を実装するには、3つのステップを踏む必要があります。
CellProcessorの実装クラスの作成
アノテーションクラスの作成
CellProcessorを作成するためのファクトリクラスの作成
以下、それぞれに対して解説していきます。
CellProcessorの実装クラスの作成
サンプルとして、任意の文字列を追加するCellProcessorを作成します。
抽象クラス
CellProcessorAdaptor
[ JavaDoc ] を継承します。
CellProcessorは、「Chain of Responsibility」パターンであるため、その構造を表現するためのクラスとなります。
インタフェースとして
StringCellProcessor
[ JavaDoc ] を実装します。この実装は特に必要ないですが、扱うカラムの値の種類を表現するめのものです。 CellProcessorを直接組み立てる時に、これらのインタフェースでchainとして追加する次のCellProcessorを限定するために使用します。
変換処理は、必ず文字列に対して行うため実装しておきます。
コンストラクタとして、chainの次の処理となるCellProcessorを引数に持つものと、持たないものを必ず2つ実装します。
メソッド
execute(...)
内で処理の実装を行います。nullの場合、次の処理に委譲するようにします。 Super CSVの既存のCellProcessorではメソッドvalidateInputNotNull(...)を呼びnullチェックを行いますが、 本ライブラリではnullに対する処理は他のCellProcessorで行うため、次の処理に渡します。
変換した値を次の処理に渡します。
1import org.supercsv.cellprocessor.CellProcessorAdaptor;
2import org.supercsv.cellprocessor.ift.CellProcessor;
3import org.supercsv.cellprocessor.ift.StringCellProcessor;
4import org.supercsv.util.CsvContext;
5
6// 独自の変換用のCellProcessor
7public class CustomConversion extends CellProcessorAdaptor implements StringCellProcessor {
8
9 private String text;
10
11 public CustomConversion(final String text) {
12 super();
13 checkPreconditions(text);
14 this.text = text;
15 }
16
17 public CustomConversion(final String text, final CellProcessor next) {
18 super(next);
19 checkPreconditions(text);
20 this.text = text;
21 }
22
23 // コンストラクタで渡した独自の引数のチェック処理
24 private static void checkPreconditions(final String text) {
25 if(text == null) {
26 throw new NullPointerException("text should not be null.");
27 }
28 }
29
30 @Override
31 public <T> T execute(final Object value, final CsvContext context) {
32 if(value == null) {
33 // nullの場合、次の処理に委譲します。
34 return next.execute(value, context);
35 }
36
37 // 最後尾に文字列を足す
38 final String result = value.toString() + text;
39
40 // 変換した値を次の処理に委譲します。
41 return next.execute(result, context);
42 }
43
44}
変換処理用のアノテーションクラスの作成
@Target
として、ElementType.FIELD
とElementType.ANNOTATION_TYPE
の2つを指定します。通常はFieldのみで問題ないですが、 アノテーションを合成 するときがあるため、 ANNOTATION_TYPE も追加しておきます。
@Repeatable
として、複数のアノテーションを設定できるようにします。内部クラスのアノテーションとして、 List を定義します。
変換用のアノテーションと示すためのメタアノテーション
@CsvConversion
[ JavaDoc ]を指定します。共通の属性として、
cases
とgroups
、order
を定義します。固有の属性 として、
text
を定義します。これはCellProcessorに渡す値となります。
1import java.lang.annotation.Documented;
2import java.lang.annotation.ElementType;
3import java.lang.annotation.Repeatable;
4import java.lang.annotation.Retention;
5import java.lang.annotation.RetentionPolicy;
6import java.lang.annotation.Target;
7
8import com.github.mygreen.supercsv.annotation.conversion.CsvConversion;
9import com.github.mygreen.supercsv.builder.BuildCase;
10
11
12// 独自の変換用のアノテーション
13@Target({ElementType.FIELD, ElementType.ANNOTATION_TYPE})
14@Retention(RetentionPolicy.RUNTIME)
15@Documented
16@Repeatable(CsvCustomConversion.List.class)
17@CsvConversion(CustomConversionFactory.class) // ファクトリクラスを指定
18public @interface CsvCustomConversion {
19
20 // 固有の属性 - 追加する値を指定します。
21 String text();
22
23 // 共通の属性 - ケース
24 BuildCase[] cases() default {};
25
26 // 共通の属性 - グループ
27 Class<?>[] groups() default {};
28
29 // 共通の属性 - 並び順
30 int order() default 0;
31
32 // 繰り返しのアノテーションの格納用アノテーションの定義
33 @Target({ElementType.FIELD, ElementType.ANNOTATION_TYPE})
34 @Retention(RetentionPolicy.RUNTIME)
35 @Documented
36 @interface List {
37
38 CsvCustomConversion[] value();
39 }
40}
変換処理用のファクトリクラスの作成
アノテーションをハンドリングして、CellProcessorを作成するためのファクトリクラスを作成します。
インタフェース
ConversionProcessorFactory
[ JavaDoc ] を実装します。独自のCellProcessorのCustomConversionのインスタンスを作成します。
Chainの次の処理となるCellProcessorの変数「next」は、空であることがあるため、コンストラクタで分けます。
1import com.github.mygreen.supercsv.builder.BuildType;
2import com.github.mygreen.supercsv.builder.Configuration;
3import com.github.mygreen.supercsv.builder.FieldAccessor;
4import com.github.mygreen.supercsv.cellprocessor.ConversionProcessorFactory;
5import com.github.mygreen.supercsv.cellprocessor.format.TextFormatter;
6
7public class CustomConversionFactory implements ConversionProcessorFactory<CsvCustomConversion> {
8
9 @Override
10 public Optional<CellProcessor> create(CsvCustomConversion anno, Optional<CellProcessor> next,
11 FieldAccessor field, TextFormatter<?> formatter, Configuration config) {
12
13 // CellProcessorのインスタンスを作成します
14 final CustomConversion processor = next.map(n -> new CustomConversion(anno.text(), n))
15 .orElseGet(() -> new CustomConversion(anno.text()));
16
17 return Optional.of(processor);
18
19 }
20
21}