最初に。参考にしたページ
- 本家ページ -> opencsv – General
- API ドキュメント -> Overview (opencsv 4.1 API)
- リポジトリ -> opencsv download | SourceForge.net
- 実際のエクスポート使用例 -> java-read-write-csv-file/OpenCSVWriter.java at master · callicoder/java-read-write-csv-file
OpenCSV を使用した POJO インポート
エスケープ文字について
- 半角ダブルクオーテーション ” をクオート文字、およびエスケープ文字に指定するとエラー (java.lang.UnsupportedOperationException) となってしまう。
- では、エスケープ文字として半角ダブルクオーテーションを使用できないかと思うが、そんなことはなかった。
- 半角バックスラッシュ(半角エンマーク) ¥ をエスケープ文字として指定してみたが、半角ダブルクオーテーションもエスケープ文字として使用できた。
- 同じく疑問、というか、ハマった人もいたみたいです。 opencsv / Feature Requests / #72 Allow double quote as escape character AND as quote character
エラーとなった場合の出力
Caught: java.lang.UnsupportedOperationException: The separator, quote, and escape characters must be different! java.lang.UnsupportedOperationException: The separator, quote, and escape characters must be different! at com.opencsv.CSVParser.<init>(CSVParser.java:211) at com.opencsv.CSVParserBuilder.build(CSVParserBuilder.java:138) at com.opencsv.bean.CsvToBeanBuilder.buildParser(CsvToBeanBuilder.java:193) at com.opencsv.bean.CsvToBeanBuilder.build(CsvToBeanBuilder.java:145) at com.opencsv.bean.CsvToBeanBuilder$build$0.call(Unknown Source) at ImportPojo.run(ImportPojo.groovy:11)
POJO インポート例
実行コードです。
// https://mvnrepository.com/artifact/com.opencsv/opencsv @Grapes( @Grab(group='com.opencsv', module='opencsv', version='4.1') ) import com.opencsv.CSVReader import com.opencsv.bean.CsvToBeanBuilder println "入力" List<Customer> customers = new CsvToBeanBuilder(new FileReader("input.csv")) .withSeparator(',' as char) .withQuoteChar('"' as char) // \ をエスケープ文字に指定したが、" もエスケープ文字になっている .withEscapeChar('\\' as char) .withType(Customer.class).build().parse() customers.eachWithIndex { record,i -> println "${i}行目----------" println "name[${record.name}]" println "age[${record.age}]" }
POJO クラスです。
import com.opencsv.bean.CsvBindByName public class Customer { @CsvBindByName(column = "氏名") public String name @CsvBindByName(column = "年齢") public String age }
CSV ファイルです。
"氏名","年齢" "岩田\"一恵",41 "東""宏行",36 梅沢 照生,38 "児島, りえ",65
実行結果です。
$ groovy ImportPojo.groovy 入力 0行目---------- name[岩田"一恵] age[41] 1行目---------- name[東"宏行] age[36] 2行目---------- name[梅沢 照生] age[38] 3行目---------- name[児島, りえ] age[65] $
OpenCSV を使用した POJO インポート
まとめメモ
- POJO クラスのプラパティは、public アクセス修飾子を付けてはいけない。エラーとなる。
- クラス宣言にアクセス修飾子を付けるのは問題ない。
- デフォルトのエスケープ文字は半角ダブルクオーテーション ” だった。
- デフォルトで、区切り文字が付与され、それは半角ダブルクオーテーション ” だった。
- 出力される CSV のカラムの順番は、POJO クラスのプロパティをソートした昇順となる(少なくとも opencsv 4.1 では)。
POJO クラスのプロパティに public アクセス修飾子を付けた結果
インポートで使用した Customer.groovy そそのまま使用すると、次のエラーとなりました><。
$ groovy ExportPojo.groovy 出力 Exception in thread "pool-1-thread-1" Exception in thread "pool-1-thread-2" com.opencsv.exceptions.CsvBeanIntrospectionException: An introspection error was thrown while attempting to manipulate property age of bean Customer. at com.opencsv.bean.AbstractBeanField.write(AbstractBeanField.java:248) at com.opencsv.bean.concurrent.ProcessCsvBean.writeWithReflection(ProcessCsvBean.java:80) at com.opencsv.bean.concurrent.ProcessCsvBean.run(ProcessCsvBean.java:107) at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149) at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624) at java.lang.Thread.run(Thread.java:748) Caused by: java.lang.NoSuchMethodException: Unknown property 'age' on class 'class Customer' at org.apache.commons.beanutils.PropertyUtilsBean.getSimpleProperty(PropertyUtilsBean.java:1269) at com.opencsv.bean.AbstractBeanField.write(AbstractBeanField.java:245) ... 5 more com.opencsv.exceptions.CsvBeanIntrospectionException: An introspection error was thrown while attempting to manipulate property age of bean Customer. at com.opencsv.bean.AbstractBeanField.write(AbstractBeanField.java:248) at com.opencsv.bean.concurrent.ProcessCsvBean.writeWithReflection(ProcessCsvBean.java:80) at com.opencsv.bean.concurrent.ProcessCsvBean.run(ProcessCsvBean.java:107) at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149) at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624) at java.lang.Thread.run(Thread.java:748) Caused by: java.lang.NoSuchMethodException: Unknown property 'age' on class 'class Customer' at org.apache.commons.beanutils.PropertyUtilsBean.getSimpleProperty(PropertyUtilsBean.java:1269) at com.opencsv.bean.AbstractBeanField.write(AbstractBeanField.java:245) ... 5 more Caught: java.lang.RuntimeException: There was an unrecoverable error while writing beans. java.lang.RuntimeException: There was an unrecoverable error while writing beans. at com.opencsv.bean.StatefulBeanToCsv.write(StatefulBeanToCsv.java:329) at com.opencsv.bean.StatefulBeanToCsv$write.call(Unknown Source) at ExportPojo.run(ExportPojo.groovy:26) Caused by: java.lang.NoSuchMethodException: Unknown property 'age' on class 'class Customer' at org.apache.commons.beanutils.PropertyUtilsBean.getSimpleProperty(PropertyUtilsBean.java:1269) at com.opencsv.bean.AbstractBeanField.write(AbstractBeanField.java:245) at com.opencsv.bean.concurrent.ProcessCsvBean.writeWithReflection(ProcessCsvBean.java:80) at com.opencsv.bean.concurrent.ProcessCsvBean.run(ProcessCsvBean.java:107) $
POJO エクスポート例
実行ファイルです。
// https://mvnrepository.com/artifact/com.opencsv/opencsv @Grapes( @Grab(group='com.opencsv', module='opencsv', version='4.1') ) import com.opencsv.CSVWriter import com.opencsv.bean.StatefulBeanToCsv import com.opencsv.bean.StatefulBeanToCsvBuilder List<Customer> customers = [ new Customer(name: "試験太郎", age: "14"), new Customer(name: "試験\"\"花子", age: "15") ] println "出力" Writer writer = new FileWriter("output.csv") StatefulBeanToCsv beanToCsv = new StatefulBeanToCsvBuilder(writer) .build() beanToCsv.write(customers) writer.close() println "output.csv を確認して!"
POJO です。インポートのときと異なり、プロパティからアクセス修飾子を除いています。
import com.opencsv.bean.CsvBindByName public class Customer { @CsvBindByName(column = "氏名") String name @CsvBindByName(column = "年齢") String age }
実行した結果、出力されたファイルの内容です。
"年齢","氏名" "14","試験太郎" "15","試験""""花子"
おわりに
今回試したコードは、次のリポジトリのコミットにまとめました。
現在判明している、深刻な問題はとして上述しましたが次があります。
- エクスポート時、出力される CSV のカラムの順番は、POJO クラスのプロパティをソートした昇順となる(少なくとも opencsv 4.1 では)。
- よって出力される CSV カラム順番を制御するには、とりあえず、簡単に解決するには、POJO クラスのプロパティ名に接頭辞等を付けて順番を付ければ良いと思う。
とりあえずの解決策を記しましたが、あまり良くないですね><。
それはともかく、opencsv を Groovy から使えることは少なくともわかりましたので、嬉しく思います♪
以上です。