4. 値の変換方法
読み込み時の文字列を各クラスにタイプにパースする前と、書き込み時の各クラスから文字列にフォーマットした後の文字列に対して、 値を変換することができます。
例えば、トリミングや大文字に変換などを行うことができます。
4.1. 変換処理用の既存のアノテーション
既存のアノテーションとして、以下のものが用意されています。
アノテーション |
概要 |
参照 |
---|---|---|
|
前後の空白をトリミングします。 |
|
|
前後どちらか一方をトリミングします。 |
|
|
値がnullのときに他の値に変換します。 |
|
|
指定した値と一致するときにnullに変換します。 |
|
|
英字のアルファベットの大文字から小文字に変換します。 |
|
|
英字のアルファベットの小文字を大文字に変換します。 |
|
|
正規表現による置換を行います。 |
|
|
語彙による置換を行います。 |
|
|
半角文字を日本語の全角文字に変換します。 |
|
|
日本語の全角文字を半角文字に変換します。 |
|
|
一定の文字長を超える場合に切り出しを行います。 |
|
|
左側にパディングを行います。 |
|
|
右側にパディングを行います。 |
|
|
柔軟な設定でパディングを行います。 |
|
|
固定長のサイズに変換します。
詳細は、「 固定長のカラムの読み書き 」を参照してください。
|
4.1.1. 処理順序の指定
属性 order
で処理順序を指定することができます。
値が大きいほど後から実行されます。
値が同じ場合は、アノテーションのFQCN(完全限定クラス名)の昇順で実行されます。
属性orderを省略した場合は、デフォルト値
0
が適用されます。
読み込み時、書き込み時とも同じ処理順序になります。
属性
order
が付与されていないアノテーションは順番が付与されているものよりも後になります。
1import com.github.mygreen.supercsv.annotation.CsvBean;
2import com.github.mygreen.supercsv.annotation.CsvColumn;
3
4import com.github.mygreen.supercsv.annotation.conversion.*;
5
6@CsvBean
7public class SampleCsv {
8
9 // 空白の場合、トリミングして空文字となった場合に入力値なしと判断して、nullに変換します。
10 @CsvColumn(number=1)
11 @CsvTrim(order=1)
12 @CsvNullConvert(value="", order=2)
13 private String comment;
14
15 // getter/setterは省略
16}
4.1.2. 処理ケースの指定
属性 cases
で、アノテーションを適用するケースとして「読み込み時」「書き込み時」を限定することができます。
列挙型
BuildCase
で指定します。BuildCase.Read
が読み込み時、BuildCase.Write
が書き込み時を表します。
属性の値が空(配列が空)の場合、または、属性 cases を指定しない場合は、全てのケースに該当します。
既存のアノテーションは、基本的に全て属性値が空が設定され、全てのケースに該当します。
1import com.github.mygreen.supercsv.annotation.CsvBean;
2import com.github.mygreen.supercsv.annotation.CsvColumn;
3import com.github.mygreen.supercsv.annotation.conversion.*;
4import com.github.mygreen.supercsv.builder.BuildCase;
5
6@CsvBean
7public class SampleCsv {
8
9 // 空白の場合、トリミングして空文字となった場合に入力値なしと判断して、nullに変換します。
10 @CsvColumn(number=1)
11 @CsvTrim(order=1, cases={}) // 全てのケースに適用
12 @CsvNullConvert(value="N/A", cases=BuildCase.Read) // 読み込み時のみ適用
13 @CsvDefault(value="N/A", cases=BuildCase.Write) // 書き込み時のみ適用
14 private String comment;
15
16 // getter/setterは省略
17}
4.1.3. グループの指定
属性 groups
で、グループ用クラスを指定することで、属性 cases より柔軟に適用するケースをを限定することができます。
Bean Validation のgroupと同じような考え方ですが、適用される順序は関係ありません。
本ライブラリでは、順序を指定したいときは、属性 order を指定します。
属性を指定しない(空の)場合は、デフォルトのグループ
com.github.mygreen.supercsv.annotation.DefaultGroup
が適用されたと同じ意味になります。Bean Validationのデフォルトグループ
javax.validation.groups.Default
とは異なるため、特にBeanValidationのアノテーションと混在させる場合は注意してください。
グループ用クラスは、実装が必要ないため、通常はインタフェースで作成します。
1import com.github.mygreen.supercsv.annotation.CsvBean;
2import com.github.mygreen.supercsv.annotation.CsvColumn;
3import com.github.mygreen.supercsv.annotation.DefaultGroup;
4
5import com.github.mygreen.supercsv.annotation.conversion.*;
6
7@CsvBean
8public class SampleCsv {
9
10 @CsvColumn(number=1)
11 @CsvHalfChar(order=1)
12 @DefaultValue(value="10", groups=AdminGroup.class, order=2)
13 @DefaultValue(value="0", groups=NormalGroup.class, order=2)
14 private Integer value;
15
16 // getter/setterは省略
17}
18
19// グループ用クラスの作成
20public static interface AdminGroup {}
21public static interface NormalGroup {}
実行時は、CsvAnnotationBeanReader/CsvAnnotationBeanWriter/BeanMappingFactory
の引数で指定します。
1import com.github.mygreen.supercsv.builder.BeanMapping;
2import com.github.mygreen.supercsv.builder.BeanMappingFactory;
3import com.github.mygreen.supercsv.io.CsvAnnotationBeanReader;
4import com.github.mygreen.supercsv.io.CsvAnnotationBeanWriter;
5
6import java.nio.charset.Charset;
7import java.nio.file.Files;
8import java.io.File;
9import java.util.ArrayList;
10import java.util.List;
11
12import org.supercsv.prefs.CsvPreference;
13
14
15public class Sample {
16
17 // 読み込み時のグループの指定
18 public void sampleRead() {
19
20 CsvAnnotationBeanReader<SampleCsv> csvReader = new CsvAnnotationBeanReader<>(
21 SampleCsv.class,
22 Files.newBufferedReader(new File("sample.csv").toPath(), Charset.forName("Windows-31j")),
23 CsvPreference.STANDARD_PREFERENCE,
24 DefaultGroup.class, AdminGroup.class); // デフォルトとAdminのグループクラスを指定する。
25
26 //... 以下省略
27
28 }
29
30 // 書き込み時のグループの指定
31 public void sampleWrite() {
32
33 CsvAnnotationBeanWriter<SampleCsv> csvWriter = new CsvAnnotationBeanWriter<>(
34 SampleCsv.class,
35 Files.newBufferedWriter(new File("sample.csv").toPath(), Charset.forName("Windows-31j")),
36 CsvPreference.STANDARD_PREFERENCE,
37 DefaultGroup.class, NormalGroup.class); // デフォルトとNoraml用のグループクラスを指定する。
38
39 //... 以下省略
40
41 }
42
43 // BeanMapping作成時の指定
44 public void sampleBeanMapping() {
45
46 // BeanMappingの作成
47 BeanMappingFactory mappingFactory = new BeanMappingFactory();
48 BeanMapping<SampleCsv> beanMapping = mappingFactory.create(SampleCsv.class,
49 DefaultGroup.class, NormalGroup.class); // デフォルトとNoraml用のグループクラスを指定する。
50
51 CsvAnnotationBeanReader<SampleCsv> csvReader = new CsvAnnotationBeanReader<>(
52 beanMapping,
53 Files.newBufferedReader(new File("sample.csv").toPath(), Charset.forName("Windows-31j")),
54 CsvPreference.STANDARD_PREFERENCE);
55
56 //... 以下省略
57 }
58
59}
4.2. 独自の変換処理の作成方法
独自の変換処理を実装するには、3つのステップを踏む必要があります。
CellProcessorの実装クラスの作成
アノテーションクラスの作成
CellProcessorを作成するためのファクトリクラスの作成
以下、それぞれに対して解説していきます。
4.2.1. 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}
4.2.2. 変換処理用のアノテーションクラスの作成
@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}
4.2.3. 変換処理用のファクトリクラスの作成
アノテーションをハンドリングして、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}