java OpenCsv 使用 BeanToCsv + HeaderColumnNameTranslateMappingStrategy 写入错误的列名
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/33778223/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
OpenCsv writes wrong column names with BeanToCsv + HeaderColumnNameTranslateMappingStrategy
提问by Baduel
I'm using opencsv 3.6
in order to create a csv file starting from a java bean.
我正在使用opencsv 3.6
以创建一个从 java bean 开始的 csv 文件。
First of all, I tried this code:
首先,我尝试了这段代码:
import com.opencsv.CSVReader;
import com.opencsv.CSVWriter;
import com.opencsv.bean.BeanToCsv;
import com.opencsv.bean.HeaderColumnNameTranslateMappingStrategy;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;
public class CustomBean {
private String name;
private String surname;
public CustomBean(String n, String s) {
this.name = n;
this.surname = s;
}
public void setName(String name) {
this.name = name;
}
public String getName() {
return name;
}
public void setSurname(String surname) {
this.surname = surname;
}
public String getSurname() {
return surname;
}
public static void main(String[] args) {
Map<String,String> mapping = new HashMap<String,String>();
mapping.put("COLUMN1","name");
mapping.put("COLUMN2","surname");
HeaderColumnNameTranslateMappingStrategy<CustomBean> strategy = new HeaderColumnNameTranslateMappingStrategy<CustomBean>();
strategy.setType(CustomBean.class);
strategy.setColumnMapping(mapping);
ArrayList<CustomBean> customUsers = new ArrayList<CustomBean>();
customUsers.add(new CustomBean("Kobe","Bryant"));
BeanToCsv<CustomBean> bean = new BeanToCsv<CustomBean>();
try {
CSVWriter writer = new CSVWriter(new FileWriter("testOut.csv"));
bean.write(strategy, writer, customUsers);
writer.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
But I had the following error:
但我有以下错误:
Exception in thread "main" java.lang.RuntimeException: Error writing CSV !
at com.opencsv.bean.BeanToCsv.write(BeanToCsv.java:74)
at test.CustomBean.main(CustomBean.java:63)
Caused by: java.lang.NullPointerException
at com.opencsv.bean.HeaderColumnNameTranslateMappingStrategy.getColumnName(HeaderColumnNameTranslateMappingStrategy.java:45)
at com.opencsv.bean.HeaderColumnNameMappingStrategy.findDescriptor(HeaderColumnNameMappingStrategy.java:112)
at com.opencsv.bean.BeanToCsv.processHeader(BeanToCsv.java:103)
at com.opencsv.bean.BeanToCsv.write(BeanToCsv.java:69)
... 1 more
This happens because in opencsv source code in getColumnName
method in the HeaderColumnNameTranslateMappingStrategy
class there is the following line:
发生这种情况是因为在类的getColumnName
方法中的opencsv 源代码中HeaderColumnNameTranslateMappingStrategy
有以下行:
return col < header.length ? columnMapping.get(header[col].toUpperCase()) : null;
Therefore, header
is null. This is true, in fact this class is a subclass of HeaderColumnNameMappingStrategy
class that contains the header
variable (String[]
type) that is never initialized.
因此,header
为空。这是真的,实际上这个类是HeaderColumnNameMappingStrategy
包含从未初始化的header
变量(String[]
类型)的类的子类。
The only useful method I found in this class is captureHeader
, but unfortunately it takes a CSVReader
as input.
我在这个类中找到的唯一有用的方法是captureHeader
,但不幸的是它需要一个CSVReader
作为输入。
For this reason I created an empty csv file:
为此,我创建了一个空的 csv 文件:
COLUMN1,COLUMN2
and I added the following lines at the beginning of the try/catch block:
我在 try/catch 块的开头添加了以下几行:
CSVReader reader = new CSVReader(new FileReader("testIn.csv"));
strategy.captureHeader(reader);
In this way (that I really don't like because I have to create a csv file) I have no exception, but in the result csv file the name of the columns does not follow the mapping strategy:
这样(我真的不喜欢,因为我必须创建一个 csv 文件)我也不例外,但是在结果 csv 文件中,列的名称不遵循映射策略:
"name","surname"
"Kobe","Bryant"
Two questions:
两个问题:
- How can I have the expectedresult, i.e. the right column names in the csv file?
- There is a way to not use the
CSVReader
class?
- 我怎样才能得到预期的结果,即 csv 文件中的正确列名?
- 有没有不使用
CSVReader
类的方法?
采纳答案by Krishnaraj
Looking at the source code of BeanToCsv
, the processHeader(...)
method does nothing with the supplied headers. Your only option is to create a custom strategy ( to avoid CSVReader
) and a custom BeanToCsv
as below
查看 的源代码BeanToCsv
,该processHeader(...)
方法对提供的标头没有任何作用。您唯一的选择是创建自定义策略(以避免CSVReader
)和自定义BeanToCsv
如下
public class CustomBean {
...
public static void main(String[] args) {
...
HeaderColumnNameTranslateMappingStrategy strategy = new CustomStrategy<CustomBean>();
strategy.setType(CustomBean.class);
strategy.setColumnMapping(mapping);
...
BeanToCsv bean = new CustomBeanToCsv<CustomBean>();
...
}
static class CustomStrategy<T> extends HeaderColumnNameTranslateMappingStrategy {
@Override
public void setColumnMapping(Map columnMapping) {
super.setColumnMapping(columnMapping);
header = new String[columnMapping.size()];
int i = 0;
for (Map.Entry entry : columnMapping.entrySet()) {
header[i] = entry.getKey().toUpperCase();
i++;
}
}
public String[] getHeader() {
return header;
}
}
static class CustomBeanToCsv<T> extends BeanToCsv {
@Override
protected String[] processHeader(MappingStrategy mapper) throws IntrospectionException {
if (mapper instanceof CustomStrategy) {
return ((CustomStrategy) mapper).getHeader();
} else {
return super.processHeader(mapper);
}
}
}
}
回答by Scott Conway
I have been using openCSV for five years now and I am still learning stuff about it. The issue is that the HeaderColumnNameMappingStrategy and HeaderColumnNameTranslateMappingStrategy were made for the CsvToBean. It wants a file to read to get the header out to see where the reader should read from.
我已经使用 openCSV 五年了,我仍在学习有关它的东西。问题是 HeaderColumnNameMappingStrategy 和 HeaderColumnNameTranslateMappingStrategy 是为 CsvToBean 制作的。它想要读取一个文件以获取标题以查看读者应该从哪里读取。
For the BeanToCsv class use the ColumnPositionMappingStrategy class. You give it the class you are mapping and a list of the columns you want to map and it does the rest for you.
对于 BeanToCsv 类,请使用 ColumnPositionMappingStrategy 类。你给它你正在映射的类和你想要映射的列的列表,它会为你完成剩下的工作。
Here is a little test method I wrote that worked.
这是我写的一个有效的小测试方法。
public void createUsingBeanToCsv(int numRecords, FileWriter fos) {
List<SmallRecord> smallRecords = new ArrayList<>(numRecords);
for (int i = 0; i < numRecords; i++) {
smallRecords.add(SmallRecordGenerator.createRecord(i));
}
BeanToCsv<SmallRecord> beanToCsv = new BeanToCsv<>();
ColumnPositionMappingStrategy<SmallRecord> strategy = new ColumnPositionMappingStrategy<>();
strategy.setType(SmallRecord.class);
String[] columns = new String[]{"bigDecimal_1", "name_1", "intNumber_1"};
strategy.setColumnMapping(columns);
beanToCsv.write(strategy, fos, smallRecords);
}