タツノオトシゴのブログ

主にJavaに関するものです。

Super CSV Annotation 2.0のリリース

久しぶりの更新です。

JavaCSVファイルを扱うためのライブラリ Super CSV に対してアノテーション機能を付け加えた独自のライブラリ Super CSV Annotation のver2.0をリリースしました。

主な変更点

作り直したため、互換性はなくなりましたが、基本的な使用方法は変わりません。
パッケージ名、クラス名は大きく変わっています。


機能的には変わりませんが、上記の機能に対する独自の拡張やアノテーションの追加が圧倒的に容易にできるようになりました。


機能一覧は、マニュアルの目次 を見ていただければわかります。


また、Bean Validationのように属性「groups」でアノテーションを適用するケースを絞り込めるようにしました。
よく使う、読み込み、書き込み時の区別は、別な属性「cases」でできるようにしました。


さらに、Bean Validationの使い勝手の悪い、順番の指定ができるようにしています。
順番や適用するケースが指定できることで、かなり柔軟な加工ができるようになりました。
まあ、現在、仕様策定中の Bean Validation 2.0 からは順番の指定ができるようになるそうですが。


機能的には、別なCSVライブラリ uniVocity を参考にしました。

基本的な使い方

マニュアルの内容そのままです。

pom.xmlには下記を追加。

<dependency>
    <groupId>com.github.mygreen</groupId>
    <artifactId>super-csv-annotation</artifactId>
    <version>2.0</version>
</dependency>
Beanの定義

基本的なアノテーション @CsvBean、@CsvColumn は変わりません。

ただし、@CsvColumnの番号指定は index→numberに代わり、1から指定するようにしました。
カラム数が多くなるとこれは設計書からBeanを定義するとき、個人的によくずれて定義してしまったためです。

import java.time.LocalDate;

import com.github.mygreen.supercsv.annotation.CsvBean;
import com.github.mygreen.supercsv.annotation.CsvColumn;
import com.github.mygreen.supercsv.annotation.constraint.CsvNumberMin;
import com.github.mygreen.supercsv.annotation.constraint.CsvRequire;
import com.github.mygreen.supercsv.annotation.constraint.CsvUnique;
import com.github.mygreen.supercsv.annotation.conversion.CsvDefaultValue;
import com.github.mygreen.supercsv.annotation.conversion.CsvNullConvert;
import com.github.mygreen.supercsv.annotation.format.CsvDateTimeFormat;
import com.github.mygreen.supercsv.annotation.format.CsvNumberFormat;
import com.github.mygreen.supercsv.builder.BuildCase;

@CsvBean
public class SampleCsv {

    @CsvColumn(number=1, label="ID")
    @CsvRequire                        // 必須チェックを行う
    @CsvUnique(order=1)                // 全レコード内で値がユニークかチェックする(順番指定)
    @CsvNumberMin(value="0", order=2)  // 最小値かどかチェックする(順番指定)
    private Integer id;

    @CsvColumn(number=2, label="名前")
    private String name;

    @CsvColumn(number=3, label="誕生日")
    @CsvDateTimeFormat(pattern="yyyy年MM月dd日")   // 日時の書式を指定する
    private LocalDate birthday;

    @CsvColumn(number=4, label="給料")
    @CsvNumberFormat(pattern="#,###0")                    // 数値の書式を指定する
    @CsvDefaultValue(value="N/A", cases=BuildCase.Write)  // 書き込み時に値がnull(空)の場合、「N/A」として出力します。
    @CsvNullConvert(value="N/A", cases=BuildCase.Read)    // 読み込み時に値が「N/A」のとき、nullとして読み込みます。
    private Integer salary;

    // getter/setterは省略

}
読み書きの方法

読み書きするためのクラス CsvAnnotationBeanReader/CsvAnnotationBeanWriterは大きく変わりません。
ただし、一度に読み書きする readAll()/writeAll() メソッドを追加しました。

import com.github.mygreen.supercsv.io.CsvAnnotationBeanReader;
import com.github.mygreen.supercsv.io.CsvAnnotationBeanWriter;

import java.nio.charset.Charset;
import java.nio.file.Files;
import java.io.File;
import java.util.ArrayList;
import java.util.List;

import org.supercsv.prefs.CsvPreference;

public class Sample {

    // 全レコードを一度に読み込む場合
    public void sampleReadAll() {

        CsvAnnotationBeanReader<SampleCsv > csvReader = new CsvAnnotationBeanReader<>(
                SampleCsv .class,
                Files.newBufferedReader(new File("sample.csv").toPath(), Charset.forName("Windows-31j")),
                CsvPreference.STANDARD_PREFERENCE);

        List<SampleCsv > list = csvReader.readAll();

        csvReader.close();
    }

    // レコードを1件ずつ読み込む場合
    public void sampleRead() {

        CsvAnnotationBeanReader<SampleCsv > csvReader = new CsvAnnotationBeanReader<>(
                SampleCsv .class,
                Files.newBufferedReader(new File("sample.csv").toPath(), Charset.forName("Windows-31j")),
                CsvPreference.STANDARD_PREFERENCE);

        List<SampleCsv > list = new ArrayList<>();

        // ヘッダー行の読み込み
        String headers[] = csvReader.getHeader(true);

        UserCsv record = null;
        while((record = csvReader.read()) != null) {
            list.add(record);
        }

        csvReader.close();
    }

    // 全レコードを一度に書き込む場合
    public void sampleWriteAll() {

        CsvAnnotationBeanWriter<UserCsv> csvWriter = new CsvAnnotationBeanWriter<>(
                UserCsv.class,
                Files.newBufferedWriter(new File("sample.csv").toPath(), Charset.forName("Windows-31j")),
                CsvPreference.STANDARD_PREFERENCE);

        // 書き込み用のデータの作成
        List<SampleCsv > list = new ArrayList<>();
        SampleCsv record1 = new SampleCsv ();
        record1.setNo(1);
        record1.setName("山田太郎");
        liad.add(record1);

        SampleCsv record2 = new SampleCsv ();
        record2.setNo(2);
        record2.setName("鈴木次郎");
        liad.add(record2);

        // ヘッダー行と全レコードデータの書き込み
        csvWriter.writeAll(list);

        csvWriter.close();
    }

    // レコードを1件ずつ読み込む場合
    public void sampleWrite() {

        CsvAnnotationBeanWriter<SampleCsv > csvWriter = new CsvAnnotationBeanWriter<>(
                SampleCsv .class,
                Files.newBufferedWriter(new File("sample.csv").toPath(), Charset.forName("Windows-31j")),
                CsvPreference.STANDARD_PREFERENCE);

        // ヘッダー行の書き込み
        csvWriter.writeHeader();

        // レコードのデータの書き込み
        SampleCsv record1 = new SampleCsv ();
        record1.setNo(1);
        record1.setName("山田太郎");
        csvWriter.write(record1);

        SampleCsv record2 = new SampleCsv ();
        record2.setNo(2);
        record2.setName("鈴木次郎");
        csvWriter.write(record2);

        csvWrier.flush();
        csvWrier.close();

    }
}