opencsv の HeaderColumnNameTranslateMappingStrategy を使って CSV を Bean に変換する

公開日: : 最終更新日:2014/02/01 opencsv , ,

opencsv の CSV 読み込み機能の1つで、CSV の1行目がヘッダになっている場合に Bean にマッピングする、というものがあります。

HeaderColumnNameTranslateMappingStrategy クラスを使った CSV → Bean 変換を検証してみました。

例によって検証プログラムは Github に登録してあります。

よかったら参考にしてみてください。

icatch-translate_mini

photo credit: eighteen1 via photopin cc

目次

1. HeaderColumnNameTranslateMappingStrategy クラスを使うケース

HeaderColumnNameTranslateMappingStrategy を使って CSV を Bean にマッピングできます。

この HeaderColumnNameTranslateMappingStrategy を使うケースですが、次の条件に一致するときに使用します。

  1. 読み込む CSV の1行目がヘッダになっていること
  2. ヘッダに記述されている項目名称と、マッピングする Bean のフィールド名が一致していないこと

ヘッダに記述されている項目名称と、マッピングする Bean のフィールド名が一致している場合は、HeaderColumnNameMappingStrategy を使います。

項目名称とフィールド名の紐付けですが、Map<String, String> オブジェクトを使って定義します。

2. 動作環境

2-1. Java

$ java -version
java version "1.7.0_11"
Java(TM) SE Runtime Environment (build 1.7.0_11-b21)
Java HotSpot(TM) 64-Bit Server VM (build 23.6-b04, mixed mode)

ですが、いろいろ都合があって、pom.xml にはコンパイラのバージョンを 1.6 で定義しています。

<plugin>
  <groupId>org.apache.maven.plugins</groupId>
  <artifactId>maven-compiler-plugin</artifactId>
  <version>3.0</version>
  <configuration>
    <source>1.6</source>
    <target>1.6</target>
    <encoding>UTF-8</encoding>
  </configuration>
</plugin>

2-2. Maven

この検証プログラムは Maven を使ってビルドしています。 プログラム作成時に使用した Maven のバージョンは次の通りです。

$ mvn -v
Apache Maven 3.0.4 (r1232337; 2012-01-17 17:44:56+0900)
Maven home: C:\Users\xxx\maven-3.0.4
Java version: 1.7.0_11, vendor: Oracle Corporation
Java home: C:\Program Files\Java\jdk1.7.0_11\jre
Default locale: ja_JP, platform encoding: MS932
OS name: "windows 7", version: "6.1", arch: "amd64", family: "windows"

2-3. commons-io

pom.xml を見ればそこにバージョンは書いてありますが、2.4 を使っています。

<dependency>
  <groupId>commons-io</groupId>
  <artifactId>commons-io</artifactId>
  <version>2.4</version>
</dependency>

3. 検証内容

3-1. CSV ファイル

検証に使った CSV の内容は次の通りです。

"タイトル","出版社","ページ数"
"タイトル1","出版社A",298
"タイトル2","出版社B",2980
"タイトル3","出版社C",29800

「本」の属性を表した CSV です。

左から次の属性値を定義しています。

  • タイトル
  • 出版社
  • ページ数

1行目はヘッダ行になっています。
それぞれの項目名称が、次の節で載せる Book クラスのフィールド名と一致していません。

Map<String, String> オブジェクトを使って紐付けを定義する必要があります。

3-2. Book クラス

「本」を表すクラス Book クラスは、次のように定義しました。

/**
 * 本を表すクラス。
 * 
 * CSV の内容をマッピングするためのクラス。
 * 
 * @author tomoyamkung
 *
 */
public class Book {
    
    /**
     * タイトル。
     */
    private String title;
    
    /**
     * 出版社。
     */
    private String publisher;

    /**
     * ページ数。
     */
    private int numberOfPages;

    /**
     * デフォルトコンストラクタを定義しないと <code>InstantiationException</code> が発生し parse に失敗する。
     */
    public Book() {}
    
    public Book(String title, String publisher, int numberOfPages) {
        this.title = title;
        this.publisher = publisher;
        this.numberOfPages = numberOfPages;
    }

    public String getTitle() {
        return title;
    }

    /**
     * 定義しないと <code>NullPointerException</code> が発生し parse に失敗する。
     * 
     * @param title
     */
    public void setTitle(String title) {
        this.title = title;
    }

    public String getPublisher() {
        return publisher;
    }

    /**
     * 定義しないと <code>NullPointerException</code> が発生し parse に失敗する。
     * 
     * @param publisher
     */
    public void setPublisher(String publisher) {
        this.publisher = publisher;
    }

    public int getNumberOfPages() {
        return numberOfPages;
    }

    /**
     * 定義しないと <code>NullPointerException</code> が発生し parse に失敗する。
     * 
     * @param numberOfPages
     */
    public void setNumberOfPages(int numberOfPages) {
        this.numberOfPages = numberOfPages;
    }

    /**
     * フィールド名を取得する。
     * 
     * @return
     */
    public static final String[] getFieldName() {
        return new String[]{"title", "publisher", "numberOfPages"};
    }
}

デフォルトコンストラクタと、(フィールドのスコープが private なら)セッタメソッドを定義しておかないと parse に失敗します。

3-3. テストコード

テストコードは次の通りです。

public class HeaderColumnNameTranslateMappingStrategyTest {

    private Reader reader;
    private HeaderColumnNameTranslateMappingStrategy<Book> strategy;
    
    @Before
    public void setUp() throws Exception {
        strategy = new HeaderColumnNameTranslateMappingStrategy<Book>();
        strategy.setType(Book.class);
        strategy.setColumnMapping(ヘッダに記述されている名称とBeanのフィールドを紐付けるMapを生成する());
            // ヘッダの名称とフィールドのマッピングを定義した Map オブジェクトを設定する
        
        reader = new InputStreamReader(
                HeaderColumnNameTranslateMappingStrategy.class.getClassLoader().getResourceAsStream(
                        HeaderColumnNameTranslateMappingStrategy.class.getSimpleName() + ".csv"), "UTF-8");
    }

    /**
     * ヘッダに記述されている名称と Bean のフィールド名を紐付ける Map オブジェクトを生成する。
     * 
     * 紐付けの関係は次の通り。
     * 
     * <ul>
     * <li>「タイトル」 → Book クラスの "title" フィールド</li>
     * <li>「出版社」 → Book クラスの "publisher" フィールド</li>
     * <li>「ページ数」 → Book クラスの "numberOfPages" フィールド</li>
     * </ul>
     * 
     * @return
     */
    private Map<String, String> ヘッダに記述されている名称とBeanのフィールドを紐付けるMapを生成する() {
        Map<String, String> columnMapping = new HashMap<String, String>();
        columnMapping.put("タイトル", "title");
        columnMapping.put("出版社", "publisher");
        columnMapping.put("ページ数", "numberOfPages");
        return columnMapping;
    }
    
    @After
    public void tearDown() throws Exception {
        if(reader != null) {
            reader.close();
        }
    }
    
    /**
     * HeaderColumnNameTranslateMappingStrategy を使って CSV を Bean に変換する。
     * 
     * HeaderColumnNameTranslateMappingStrategy は次の条件に一致するときに使用します。
     * 
     * <ol>
     * <li>読み込む CSV の1行目がヘッダになっていること</li>
     * <li>ヘッダに記述されている名称と、マッピングする Bean のフィールド名が一致していないこと</li>
     * </ol>
     * 
     * ヘッダに記述されている名称と、マッピングする Bean のフィールド名を紐付けるために Map<String, String> に定義します。
     * 
     * @throws Exception
     */
    @Test
    public void HeaderColumnNameTranslateMappingStrategyを使ってCSVをBeanに変換する() throws Exception {
        CsvToBean<Book> sut = new CsvToBean<Book>();
        List<Book> actual = sut.parse(strategy, reader);
        
        assertThat(actual.size(), is(3));
        
        Book book = actual.get(0);
        assertThat(book.getTitle(), is("タイトル1"));
        assertThat(book.getPublisher(), is("出版社A"));
        assertThat(book.getNumberOfPages(), is(298));
        
        book = actual.get(1);
        assertThat(book.getTitle(), is("タイトル2"));
        assertThat(book.getPublisher(), is("出版社B"));
        assertThat(book.getNumberOfPages(), is(2980));
        
        book = actual.get(2);
        assertThat(book.getTitle(), is("タイトル3"));
        assertThat(book.getPublisher(), is("出版社C"));
        assertThat(book.getNumberOfPages(), is(29800));
    }

}

“src/test/resources/HeaderColumnNameMappingStrategyTest.csv” にテスト用の CSV ファイルを置いてある、という想定です。

HeaderColumnNameTranslateMappingStrategy オブジェクトと、CSV を読み込んだ Reader オブジェクトを使って CSV → Bean にマッピングします。

CSV のヘッダ行と Book クラスのフィールドを紐付けする Map<String, String> オブジェクトの生成は “ヘッダに記述されている名称とBeanのフィールドを紐付けるMapを生成する()” で行っています。

4. まとめ

「取り込む CSV の1行目に定義してある項目名称と、マッピングするクラスのフィールド名が一致していること」という条件を満たさなくてもよいので、HeaderColumnNameTranslateMappingStrategy よりも利用する場面は多いかなと思います。

いずれにしても、覚えておくと役に立ちそうなライブラリです。

5. 検証プログラムを Github に登録しました

検証プログラムは Github に登録してあります。

よかったら参考にしてみてください。

6. その他の opencsv に関する記事

opencsv に関する記事は次の通りです。
気になる記事があったらぜひチェックしてみてください!

Googleアドセンス用(PC)

  • このエントリーをはてなブックマークに追加
  • follow us in feedly

関連記事

icatch-ColumnPositionMappingStrategy

opencsv の ColumnPositionMappingStrategy を使って CSV を Bean に変換する

opencsv を使うと、CSV を読み込んで String の配列に変換してくれます。 Strin

記事を読む

icatch-strategy_mini

opencsv の HeaderColumnNameMappingStrategy を使って CSV を Bean に変換する

opencsv の CSV 読み込み機能の1つで、CSV の1行目がヘッダになっている場合に Bea

記事を読む

CSSS85_zangyoumonita20131019500

opencsvの検証をしてみた

お客さんから CSV の解析でバグがあると指摘があり、そのバグ解消のために opencsv を検証し

記事を読む

icatch-dog-ear_mini

opencsv を使って CSV ファイルの読み込み開始行を指定する

opencsv は、読み込むファイルの開始位置を指定することができます。 わざわざ確認する必要もな

記事を読む

Googleアドセンス用(PC)

Message

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です


+ 六 = 7

次のHTML タグと属性が使えます: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>

Googleアドセンス用(PC)

icatch-jersey_multi_pathparams
Jerseyの@PathParamはスラッシュの間に複数指定できる

http://hoge-api/user/{id}.{format}

icatch-vagrant_box_customize
VagrantのBoxファイルをカスタマイズして独自のBoxファイルを作成する

配布されている Vagrant の Box ファイルを使って検証環境を

icatch-2015-006-1
バリデーションチェックにJava8のOptionalを使ってスマートに書く(自分比)

Web アプリのバリデーションチェックにアノテーションを使うことが増え

icatch-2015-005-1
ユニットテストの偏りを防ぐ命名規則の付け方

ユニットテスト名に以下の命名規則を付けるようにして二ヶ月ぐらい経った。

icatch-2015-004-1
Vagrantで起動したCentOS上のOctopressをホストOSから確認する設定

タイトルの通りだが、Vagrant を使って起動した CentOS に

→もっと見る

PAGE TOP ↑