読者です 読者をやめる 読者になる 読者になる

id:jackpot1014がアノテーションがよう分からんというのでサンプルツール作ってみた。

http://cynipe.googlecode.com/svn/trunk/csvmanager からチェックアウト出来るよ!

作ったのはCSVの列番号をアノテーションでフィールドにマッピングしてくれる奴。イメージ湧かす用サンプルなんでString型にしか対応してません。ヘッダ行もまったく考慮してません。

使い方:

  1. なんか適当なCSVを用意
  2. CSV用のモデルクラスを作る。
    • String型のフィールドで。
    • publicフィールドで
    • フィールドにCsvIndexアノテーションを付ける。
  3. CsvManagerを使って読み込みましょー。

PlayListCsv.java

public class PlayListCsv {

  @CsvIndex(0)
  public String title;

  @CsvIndex(1)
  public String artist;

  @CsvIndex(2)
  public String album;

}

CsvManagerExample.java

public class CsvManagerExample {

  public static void main(String[] args) throws IOException {
    CsvManager<PlayListCsv> manager = CsvManager.create(PlayListCsv.class);
    InputStream in = CsvManagerExample.class.getResourceAsStream("playlist.csv");
    List<PlayListCsv> models = manager.toModels(in, "UTF-8");
    System.out.println("Model-----");
    System.out.println(models);
    System.out.println();
                
    String lines = manager.toCsvLines(models);
    System.out.println("CSV-------");
    System.out.println(lines);
    System.out.println("----------");
  }
}

で、まぁ、肝になるのはCsvManager.javaの89行目からのメソッド。

CsvManager.java

protected M toModel(String[] cols)//CSVをsplitした配列
    throws AssertionError {
  M model = Reflections.newInstance(modelClass);
  for (final Field field : modelFields) {
    // フィールドからアノテーションを取って
    final CsvIndex anno = field.getAnnotation(CsvIndex.class);
    // ちょっと省略
    // アノテーションのvalue属性からCSVのインデックスを取得
    final String value = cols[anno.value()];
    // フィールドにセット
    Reflections.setValue(model, field, value);
  }
  return model;
}

と、まぁこんな感じで使います。上手く使えば結構便利で、今まで設定情報を別ファイルに書いててどこを見れば動かせるのか分からないよ!的な情報をアドバイス(注釈=アノテーション)として埋め込んであげて、その情報をもとにコードを動かせるんで、迷わせずにすむよねーという。必要な情報はそのクラスを見れば分かるよ!的に使えます。

ちなみに今回はせっかくのお遊びなんでテストをSpockで書いてみた。GroovyEclipsePluginもよくなったというので使ってみましたよ。

CsvMangerSpock.groovy
一部抜粋するとこんな感じ。

def "convert csv lines to models"() {
  setup:
  def csvManager = CsvManager.create(NormalIndexModel.class)
  def csvLines = csvOf("a,b\naa,bb\naaa,bbb")
  
  when:
  def models = csvManager.toModels(csvLines, "UTF-8")
  
  then:
  models.toString() == [
  new NormalIndexModel(foo:"a", bar:"b"),
  new NormalIndexModel(foo:"aa", bar:"bb"),
  new NormalIndexModel(foo:"aaa", bar:"bbb")
  ].toString()
}

def "creates manager with model class that doesn't have annotated field"() {
  when:
  CsvManager.create(UnannotatedModel.class)
     
  then:
  thrown(IllegalArgumentException.class)
}

さくっとテストする為にequalsをつけようとしたんだけど、groovyの==の呼び出しとかぶってしまうようで、再帰呼び出しとまらないーではまってみたりなんぞ。とりあえずtoStringでごまかした。まぁ、定形でかけるってとこと、てすとに落ちた時のメッセージが分かりやすくていいね。

GroovyEclipsePluginはリファクタも出来るようになったし、補完も昔に比べたらかなりすんなり。F3でJava側の宣言元に飛べない時なんかもあるけど、かなり満足。でもmavenizeしてるせいか、そもそもプラグインのせいか分からないんだけど、コンパイルされるタイミングがよく分からなくて、クリーンしたりしても前のソースのままだったりして結構ハマった。結局mvn testで動かしたけど。個人的にそこは全く苦にならないのでOK。

久しぶりにお遊びでコード書いてみたけど、腕折れてるせいで会社環境じゃないと時間がかかってしょうがない。会社だとHHKB2台で片方は斜めにおいてサイバーな感じでやってるんで楽なんだけども。

とまぁ、こんな感じでイメージ湧いたでしょうかね? > id:jackpot1014