独自の変換処理の作成方法

独自の変換処理を実装するには、3つのステップを踏む必要があります。

  1. CellProcessorの実装クラスの作成

  2. アノテーションクラスの作成

  3. 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.FIELDElementType.ANNOTATION_TYPE の2つを指定します。

    • 通常はFieldのみで問題ないですが、 アノテーションを合成 するときがあるため、 ANNOTATION_TYPE も追加しておきます。

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

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

  • 変換用のアノテーションと示すためのメタアノテーション @CsvConversion [ JavaDoc ]を指定します。

  • 共通の属性として、 casesgroupsorder を定義します。

  • 固有の属性 として、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}