独自のクラスタイプの対応方法

Excelのセルの値を任意のJavaのクラス型にマッピングする方法を説明します。

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

  2. CellConverterを作成するためのファクトリクラスの作成

  3. アノテーション @XlsConverter による指定

CellConverterの実装クラスの作成

Excelのセルの値をJavaの任意のクラスにマッピングするには、CellConveterを実装します。

次のように、タイトルとリストが組み合わさったテキストをCustomTypeクラスにマッピングするとします。

マッピング対象の値
タイトル
- リスト1
- リスト2
マッピングするJavaクラス
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
public class CustomType {

     /** タイトル */
     private String title;

     /** リスト */
     private List<String> items;

     /**
      * リストの要素を追加する
      * @param リストの要素
      */
     public void addItem(String item) {
         if(items == null) {
             this.items = new ArrayList<>();
         }
         this.items.add(item);
     }

     // setter, getterは省略

 }
  • インタフェース com.gh.mygreen.xlsmapper.cellconvert.CellConverter を実装します。

    • 実際には、ユーティリティメソッドがそろっている、com.gh.mygreen.xlsmapper.cellconverter.BaseCellConverter を継承して実装します。

    • 読み込み時、書き込み時のそれぞれのメソッドを実装します。

      • 文字列に対するマッピングの場合は、TextFormatterparse/format メソッドに委譲します。

      • TextFormatter の実装は、後の CellConverterFactory の作成にて実装します。

    • 実装のサンプルは、パッケージ com.gh.mygreen.xlsmapper.cellconvert.impl 以下に格納されているクラスを参照してください。

CellConverterの実装
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
public class CustomCellConverter extends BaseCellConverter<CustomType> {

    public CustomCellConverter(FieldAccessor field, Configuration config) {
        super(field, config);
    }

    /**
     * セルをJavaのオブジェクト型に変換します。
     * @param evaluatedCell 数式を評価済みのセル
     * @param formattedValue フォーマット済みのセルの値。トリミングなど適用済み。
     * @return 変換した値を返す。
     * @throws TypeBindException 変換に失敗した場合
     */
    @Override
    protected CustomType parseCell(Cell evaluatedCell, String formattedValue) throws TypeBindException {

        try {
            // 文字列を変換するときには、TextFormatter#parseに委譲します。
            return getTextFormatter().parse(formattedValue);
        } catch(TextParseException e) {
            throw newTypeBindExceptionOnParse(e, evaluatedCell, formattedValue);
        }

    }

    /**
     * 書き込み時のセルに値と書式を設定します。
     * @param cell 設定対象のセル
     * @param cellValue 設定対象の値。
     * @throws TypeBindException 変換に失敗した場合
     */
    @Override
    protected void setupCell(Cell cell, Optional<CustomType> cellValue) throws TypeBindException {

        if(cellValue.isPresent()) {
            // 文字列を変換するときには、TextFormatter#formatに委譲します。
            String text = getTextFormatter().format(cellValue.get());
            cell.setCellValue(text);
        } else {
            cell.setCellType(CellType.BLANK);
        }
    }

}

CellConverterFactoryの実装クラスの作成

  • インタフェース com.gh.mygreen.xlsmapper.cellconverter.CellConverterFactory を実装する。

    • 実際には、サポートメソッドが揃っている com.gh.mygreen.xlsmapper.cellconverter.CellConverterFactorySupport を継承し作成します。

    • 実装のサンプルは、パッケージ com.gh.mygreen.xlsmapper.cellconvert.impl 以下に格納されているクラスを参照してください。

  • 文字列に対する処理として、 TexFormatter を実装します。

    • TextFromatter#parse は、初期値を @XlsDefaltValue("<初期値>") で与えられているときに、文字列をオブジェクトに変換する際に使用します。

    • TextFormatter#format は、Validationのエラーメッセージ中で値をフォーマットするときに、オブジェクトを文字列に変換する際に使用します。

CellConverterFactoryの実装
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
/**
 * フィールドに対するセル変換クラスを作成する。
 * @param accessor フィールド情報
 * @param config システム設定
 * @return セルの変換クラス。
 */
public class CustomCellConverterFactory extends CellConverterFactorySupport<CustomType>
            implements CellConverterFactory<CustomType> {

    @Override
    public CustomCellConverter create(FieldAccessor accessor, Configuration config) {
        final CustomCellConverter cellConverter = new CustomCellConverter(accessor, config);

        // トリムなどの共通の処理を設定する
        setupCellConverter(cellConverter, accessor, config);

        return cellConverter;
    }

    @Override
    protected void setupCustom(AbstractCellConverter<CustomType> cellConverter, FieldAccessor field, Configuration config) {
        // 必要があれば実装する。
    }

    /**
     * {@link TextFormatter}のインスタンスを作成する。
     * @param field フィールド情報
     * @param config システム情報
     * @return {@link TextFormatter}のインスタンス
     */
    @Override
    protected TextFormatter<CustomType> createTextFormatter(FieldAccessor field, Configuration config) {

        return new TextFormatter<CustomType>() {

            @Override
            public CustomType parse(String text) throws TextParseException {

                if(StringUtils.isEmpty(text)) {
                    return null;
                }

                // 改行で分割する
                String[] split = text.split("\r\n|\n");

                if(split.length <= 1) {
                    // 1行以下しかない場合は、例外とする
                    throw new TextParseException(text, CustomType.class);
                }

                CustomType data = new CustomType();
                data.setTitle(split[0]);

                for(int i=1; i < split.length; i++) {
                    String item = split[i];
                    if(item.startsWith("- ")) {
                        // リストの記号を削除する
                        item = item.substring(2);
                    }
                    data.addItem(item);
                }

                return data;
            }

            @Override
            public String format(CustomType value) {
                if(value == null) {
                    return "";
                }

                StringBuilder text = new StringBuilder();
                text.append(value.getTitle())
                    .append("\n");

                // 改行で繋げる
                text.append(value.getItems().stream().collect(Collectors.joining("\n")));
                return text.toString();
            }

        };
    }

}

作成したCellConverterの使用方法

作成したCellConverterを使用するには、2つの方法があります。

@XlsConverter を使用する方法

作成した CellConverterFactoryの実装クラスをアノテーション @XlsConverter に指定します。

XlsConverterアノテーションによる指定
1
2
3
4
5
6
7
public class SampleRecord {

     // 独自のCellConverterFactoryの指定
     @XlsConverter(CustomCellConverterFactory.class)
     @XlsColumn(columnName="TODOリスト")
     private CustomType value;
}

CellConverterRegistry を使用する方法

作成した CellConverterFactoryの実装クラスのインスタンスを XlsMapperConfg#getConverterRegistry() に登録します。

CellConverterRegistryへの登録
1
2
3
4
// 独自のCellConverterFactoryの登録
XlsMapper mapper = new XlsMapper();
CellConverterRegistry cellConverterRegistry = mapper.getConiguration().getConverterRegistry();
cellConverterRegistry.registerConverter(CustomType.class, new CustomCellConverterFactory());