【Java】CSVの煩わしさを軽減!?!?CSVマッピングライブラリの紹介

こんにちは!あさもっちゃんです!!!!

大量な情報のやり取りを行う時、WebAPIを用いたシステムではJSONがよく使われます。 JSONの特徴は、「key : value」構造かつ入れ子構造であり、複雑なオブジェクトの内部値を表現するのに適しています。 しかし、カッコが多かったりして、人が読み書きするには少し不便だったりします。

Web系ではない普通のエンジニアがデータをやり取りする際によく使われるのはCSVだったりします。 CSVは1〜2次元構造までしか表現出来ないなどの制約がありますが、 一行が一つの塊として扱えるため、大量のデータを取り扱う際に非常に見やすかったりします。 また、Excelなどの二次元構造を取り扱うアプリケーションも多く、馴染みが深い構造でもあります。

今回は、そんなCSVを簡単に扱えるライブラリをご紹介したいと思います!!!!

時代の潮流に追いついた!?Annotationを使ったCSVマッパー!!!!

CSVライブラリにも色々あります。 ヘッダの文字を与えてやるとPOJOマッピングするものとか、行番号でPOJOマッピングするとか。 はたまた、マッピングせずに文字配列だけ取り出すものとか。 しかし、システムとして取り扱う場合はマッピングされていた方が取り回しも良いです。

今回は、設定ファイルも必要ない、ヘッダー名を合わせる必要もない、 「Annotation」を利用してCSVマッピングするライブラリをご紹介します!!!!

Super CSV Annotation

このライブラリの特徴は、

  1. 行番号を指定してマッピングを行う
  2. それぞれの値の論理名(label)を設定できる
  3. それぞれの値の出力フォーマットを指定できる

という機能をAnnotationで実装しているところにあります。

パーサーライブラリとしてAnnotationを利用する利点は、

  1. マッピングルールを変数の属性値的に記述できる
  2. マッピングを行うロジックに論理名や物理名を記述する必要がなくなる

になります。

実際どのようなソースコードになるか見てみましょう。

// POJOクラス

package org.pickles.dataformat.csv;

import com.github.mygreen.supercsv.annotation.CsvBean;
import com.github.mygreen.supercsv.annotation.CsvColumn;
import com.github.mygreen.supercsv.annotation.format.CsvBooleanFormat;
import com.github.mygreen.supercsv.annotation.format.CsvDateTimeFormat;
import com.github.mygreen.supercsv.annotation.format.CsvNumberFormat;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

@CsvBean
public class Person {

    @CsvColumn(number=1, label="ID")
    private long id;

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

    @CsvColumn(number=3, label="誕生日")
    @CsvDateTimeFormat(pattern="yyyy/MM/dd")
    private Date birthday;

    @CsvColumn(number=4, label="学生")
    @CsvBooleanFormat(
            readForTrue={"○", "true", "yes"},
            readForFalse={"×", "false", "no", ""},
            writeAsTrue="○",
            writeAsFalse="")
    private boolean student;

    @CsvColumn(number=5, label="身長")
    @CsvNumberFormat(precision=4, rounding= RoundingMode.HALF_UP)
    private BigDecimal height;

    @CsvColumn(number=6, label="体重")
    @CsvNumberFormat(precision=5, rounding= RoundingMode.HALF_UP)
    private BigDecimal weight;

  // getter, setterは省略
}

POJOクラスの変数にAnnotationがついているのがわかります。 @CsvColumnというAnnotationで、列番号と列名を定義しています。 また、それぞれの型に合わせた@Csv〇〇Formatというものでフォーマットの定義もしています。 どうですか?どの変数がCSVのどの情報に該当するか、非常にわかりやすいと思いませんか?

次に、実際にマッピングするクラスを見てみましょう。

// CSVマッピングクラス

package org.pickles.dataformat.csv;

import com.github.mygreen.supercsv.io.CsvAnnotationBeanReader;
import com.github.mygreen.supercsv.io.CsvAnnotationBeanWriter;
import org.supercsv.prefs.CsvPreference;

import java.io.*;
import java.util.ArrayList;
import java.util.List;

public class CSVTools {

    public static <T> String toCSVString(List<T> beans, Class<T> type){

        StringWriter writer = new StringWriter();

        try(CsvAnnotationBeanWriter<T> csvWriter = new CsvAnnotationBeanWriter<>(
                type, writer, CsvPreference.STANDARD_PREFERENCE)){

            csvWriter.writeHeader();

            beans.forEach(item -> {
                try {
                    csvWriter.write(item);
                } catch (IOException e) {
                    e.printStackTrace();
                }
            });

        } catch (IOException e) {
            e.printStackTrace();
        }

        return writer.toString();
    }

    public static <T> List<T> parseFromCSV(String csv, Class<T> type) {

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

        try(CsvAnnotationBeanReader<T> csvReader = new CsvAnnotationBeanReader<>(
                type, new BufferedReader(new StringReader(csv)), CsvPreference.STANDARD_PREFERENCE)) {

            csvReader.getHeader(true);

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

        } catch (IOException e) {
            e.printStackTrace();
        }

        return list;
    }
}

なんと!!!!ライブラリ特有のステップが、文字列変換に2行、POJOマッピングに3行しか現れません!!!! しかも!!!!マッピングに必要な情報を記述するようなロジックが、Utilのメソッドに存在しないです!!!! これはめちゃめちゃ読みやすい。関心事がきちんと分割されてて、とてもいい感じのソースコードですね。

文字列変換では、専用クラスをnewして、writeメソッドを呼ぶだけ。 POJOマッピングでは、専用クラスをnewして、ヘッダ情報を読んで、body情報をマッピングする。 単純明快なロジックになってて素晴らしいですね!!!!

終わりに

完全にSuper CSV Annotationをべた褒めする記事になりましたwwwww ですが、このライブラリの凄さがわかって頂けたかと思います。

データ取り込みでよく使われるCSVですが、ここまで綺麗にかけるのならあまり手間も感じずに実装が完了しそうですね!!

是非とも現場で利用してみてください!!!!

参考サイト様

公式サイト

実装したソースコード

GitHub