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

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-11-02 22:07:36  来源:igfitidea点击:

OpenCsv writes wrong column names with BeanToCsv + HeaderColumnNameTranslateMappingStrategy

javacsvopencsv

提问by Baduel

I'm using opencsv 3.6in 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 getColumnNamemethod in the HeaderColumnNameTranslateMappingStrategyclass there is the following line:

发生这种情况是因为在类的getColumnName方法中的opencsv 源代码中HeaderColumnNameTranslateMappingStrategy有以下行:

return col < header.length ? columnMapping.get(header[col].toUpperCase()) : null;

Therefore, headeris null. This is true, in fact this class is a subclass of HeaderColumnNameMappingStrategyclass that contains the headervariable (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 CSVReaderas 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:

两个问题:

  1. How can I have the expectedresult, i.e. the right column names in the csv file?
  2. There is a way to not use the CSVReaderclass?
  1. 我怎样才能得到预期的结果,即 csv 文件中的正确列名?
  2. 有没有不使用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 BeanToCsvas 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);

}