Java OpenCSV:如何使用自定义列标题和自定义列位置从POJO创建CSV文件?

Java OpenCSV:如何使用自定义列标题和自定义列位置从POJO创建CSV文件?,java,xml,csv,opencsv,Java,Xml,Csv,Opencsv,我创建了一个MappingsBean类,其中指定了CSV文件的所有列。接下来,我解析XML文件并创建MappingBean列表。然后我将数据作为报告写入CSV文件 我正在使用以下注释: public class MappingsBean { @CsvBindByName(column = "TradeID") @CsvBindByPosition(position = 0) private String tradeId; @CsvBindByName(colu

我创建了一个MappingsBean类,其中指定了CSV文件的所有列。接下来,我解析XML文件并创建MappingBean列表。然后我将数据作为报告写入CSV文件

我正在使用以下注释:

public class MappingsBean {

    @CsvBindByName(column = "TradeID")
    @CsvBindByPosition(position = 0)
    private String tradeId;

    @CsvBindByName(column = "GWML GUID", required = true)
    @CsvBindByPosition(position = 1)
    private String gwmlGUID;

    @CsvBindByName(column = "MXML GUID", required = true)
    @CsvBindByPosition(position = 2)
    private String mxmlGUID;

    @CsvBindByName(column = "GWML File")
    @CsvBindByPosition(position = 3)
    private String gwmlFile;

    @CsvBindByName(column = "MxML File")
    @CsvBindByPosition(position = 4)
    private String mxmlFile;

    @CsvBindByName(column = "MxML Counterparty")
    @CsvBindByPosition(position = 5)
    private String mxmlCounterParty;

    @CsvBindByName(column = "GWML Counterparty")
    @CsvBindByPosition(position = 6)
    private String gwmlCounterParty;
}
然后我使用
statefulbeantocvs
类写入CSV文件:

File reportFile = new File(reportOutputDir + "/" + REPORT_FILENAME);
Writer writer = new PrintWriter(reportFile);
StatefulBeanToCsv<MappingsBean> beanToCsv = new 
                              StatefulBeanToCsvBuilder(writer).build();
beanToCsv.write(makeFinalMappingBeanList());
writer.close();
File reportFile=新文件(reportOutputDir+“/”+报告文件名);
Writer Writer=新的PrintWriter(报告文件);
StatefulBeanToCsv beanToCsv=新建
StatefulBeanToCsvBuilder(writer.build();
write(makeFinalMappingBeanList());
writer.close();
这种方法的问题是,如果我使用
@CsvBindByPosition(position=0)
来控制 位置,则我无法生成列名。如果使用
@CsvBindByName(column=“TradeID”)
,则无法设置列的位置

是否有一种方法可以同时使用这两种注释,以便创建具有列标题的CSV文件并控制列位置

问候,,
Vikram Pathania

我也有类似的问题。另外,OpenCSV中没有内置功能,允许使用自定义列名排序将bean写入CSV

OpenCSV开箱即用中提供了两种主要的映射策略:

  • HeaderColumnNameMappingStrategy
    :允许基于自定义名称将CVS文件列映射到bean字段;将bean写入CSV时,这允许更改列标题名称,但我们无法控制列顺序
  • ColumnPositionMappingStrategy
    :允许根据列顺序将CSV文件列映射到bean字段;将bean写入CSV时,我们可以控制列顺序,但得到一个空的标题(实现返回
    新字符串[0]
    作为标题)
我发现实现自定义列名和排序的唯一方法是编写自定义的
MappingStrategy

第一个解决方案:快速、简单但硬编码 创建自定义映射策略:

class CustomMappingStrategy<T> extends ColumnPositionMappingStrategy<T> {
    private static final String[] HEADER = new String[]{"TradeID", "GWML GUID", "MXML GUID", "GWML File", "MxML File", "MxML Counterparty", "GWML Counterparty"};

    @Override
    public String[] generateHeader() {
        return HEADER;
    }
}
MappingsBean
类中,我们留下了
CsvBindByPosition
annotations-来控制顺序(在这个解决方案中
CsvBindByName
不需要注释)。由于自定义映射策略,标题列名包含在生成的CSV文件中

此解决方案的缺点是,当我们通过
CsvBindByPosition
注释更改列顺序时,我们还必须在自定义映射策略中手动更改
标题
常量

第二个解决方案:更灵活 第一个解决方案是可行的,但对我不好。基于
映射策略的内置实现
我提出了另一个实现:

class CustomMappingStrategy<T> extends ColumnPositionMappingStrategy<T> {
    @Override
    public String[] generateHeader() {
        final int numColumns = findMaxFieldIndex();
        if (!isAnnotationDriven() || numColumns == -1) {
            return super.generateHeader();
        }

        header = new String[numColumns + 1];

        BeanField beanField;
        for (int i = 0; i <= numColumns; i++) {
            beanField = findField(i);
            String columnHeaderName = extractHeaderName(beanField);
            header[i] = columnHeaderName;
        }
        return header;
    }

    private String extractHeaderName(final BeanField beanField) {
        if (beanField == null || beanField.getField() == null || beanField.getField().getDeclaredAnnotationsByType(CsvBindByName.class).length == 0) {
            return StringUtils.EMPTY;
        }

        final CsvBindByName bindByNameAnnotation = beanField.getField().getDeclaredAnnotationsByType(CsvBindByName.class)[0];
        return bindByNameAnnotation.column();
    }
}
类CustomMappingStrategy扩展了ColumnPositionMappingStrategy{
@凌驾
公共字符串[]generateHeader(){
final int numColumns=findMaxFieldIndex();
如果(!isAnnotationDriven()| | numColumns===-1){
返回super.generateHeader();
}
header=新字符串[numColumns+1];
豆田豆田;

对于(int i=0;i如果您没有getDeclaredAnnotationsByType方法,但需要原始字段名的名称:

beanField.getField().getName()

公共类CustomMappingStrategy扩展了ColumnPositionMappingStrategy{
@凌驾
公共字符串[]generateHeader(){
final int numColumns=findMaxFieldIndex();
如果(!isAnnotationDriven()| | numColumns===-1){
返回super.generateHeader();
}
header=新字符串[numColumns+1];
豆田豆田;

对于(int i=0;i已更正上述答案,以与较新版本匹配

package csvpojo;

import org.apache.commons.lang3.StringUtils;

import com.opencsv.bean.BeanField;
import com.opencsv.bean.ColumnPositionMappingStrategy;
import com.opencsv.bean.CsvBindByName;
import com.opencsv.exceptions.CsvRequiredFieldEmptyException;

class CustomMappingStrategy<T> extends ColumnPositionMappingStrategy<T> {
    @Override
    public String[] generateHeader(T bean) throws CsvRequiredFieldEmptyException {

super.setColumnMapping(new String[ FieldUtils.getAllFields(bean.getClass()).length]);
        final int numColumns = findMaxFieldIndex();
        if (!isAnnotationDriven() || numColumns == -1) {
            return super.generateHeader(bean);
        }

        String[] header = new String[numColumns + 1];

        BeanField<T> beanField;
        for (int i = 0; i <= numColumns; i++) {
            beanField = findField(i);
            String columnHeaderName = extractHeaderName(beanField);
            header[i] = columnHeaderName;
        }
        return header;
    }

    private String extractHeaderName(final BeanField<T> beanField) {
        if (beanField == null || beanField.getField() == null
                || beanField.getField().getDeclaredAnnotationsByType(CsvBindByName.class).length == 0) {
            return StringUtils.EMPTY;
        }

        final CsvBindByName bindByNameAnnotation = beanField.getField()
                .getDeclaredAnnotationsByType(CsvBindByName.class)[0];
        return bindByNameAnnotation.column();
    }
}

感谢这个线程,它对我真的很有用…我对提供的解决方案进行了一点增强,以便也接受POJO,其中一些字段没有注释(不意味着读/写):

公共类ColumnAndNameMappingStrategy扩展了ColumnPositionMappingStrategy{
@凌驾
公共字符串[]generateHeader(T bean)抛出CsvRequiredFieldEmptyException{
setColumnMapping(新字符串[getAnnotatedFields(bean)]);
final int numColumns=getAnnotatedFields(bean);
final int totalFieldNum=findMaxFieldIndex();
如果(!isAnnotationDriven()| | numColumns===-1){
返回super.generateHeader(bean);
}
字符串[]头=新字符串[numColumns];
豆田豆田;

对于(int i=0;i我希望实现双向导入/导出-能够将生成的CSV导入回POJO,反之亦然

我无法为此使用@CsvBindByPosition,因为在这种情况下,已自动选择-ColumnPositionMappingStrategy。每个文档:

我用什么来实现目标: 用于预定义字符串排序的自定义比较器:

public class OrderedComparatorIgnoringCase implements Comparator<String> {
    private List<String> predefinedOrder;

    public OrderedComparatorIgnoringCase(String[] predefinedOrder) {
        this.predefinedOrder = new ArrayList<>();
        for (String item : predefinedOrder) {
            this.predefinedOrder.add(item.toLowerCase());
        }
    }

    @Override
    public int compare(String o1, String o2) {
        return predefinedOrder.indexOf(o1.toLowerCase()) - predefinedOrder.indexOf(o2.toLowerCase());
    }
}
public static void main(String[] args) throws Exception {
    //omitted code from writing
    String csv = convertToCsv(localBusinessTrainingPairsDTO, mappingStrategy);

    //Exported CSV should be compatible for further import
    File temp = File.createTempFile("tempTrainingPairs", ".csv");
    temp.deleteOnExit();
    BufferedWriter bw = new BufferedWriter(new FileWriter(temp));
    bw.write(csv);
    bw.close();
    MultipartFile multipartFile = new MockMultipartFile("tempTrainingPairs.csv", new FileInputStream(temp));

    List<LocalBusinessTrainingPairDTO> localBusinessTrainingPairDTOList = convertFromCsv(multipartFile, LocalBusinessTrainingPairDTO.class);
}
CustomBeanToCSVMappingStrategy<Pojo> mappingStrategy = new CustomBeanToCSVMappingStrategy<>();
            mappingStrategy.setType(Pojo.class);

StatefulBeanToCsv<Pojo> beanToCsv = new StatefulBeanToCsvBuilder<Pojo>(writer)
                    .withSeparator(CSVWriter.DEFAULT_SEPARATOR)
                    .withMappingStrategy(mappingStrategy)
                    .build();

beanToCsv.write(pojoList);
公共类OrderedComparatorIgnoringCase实现了Comparator{
私有列表预定义顺序;
public OrderedComparatorIgnoringCase(字符串[]预定义顺序){
this.predefinedOrder=新的ArrayList();
for(字符串项:预定义订单){
this.predefinedOrder.add(item.toLowerCase());
}
}
@凌驾
公共整数比较(字符串o1、字符串o2){
返回预定义的order.indexOf(o1.toLowerCase())-predefinedOrder.indexOf(o2.toLowerCase());
}
}
POJO的有序写作(对初始问题的回答)

public static void main(String[] args) throws Exception {
     List<LocalBusinessTrainingPairDTO> localBusinessTrainingPairsDTO = new ArrayList<>();
     LocalBusinessTrainingPairDTO localBusinessTrainingPairDTO = new LocalBusinessTrainingPairDTO();
     localBusinessTrainingPairDTO.setLeftId(1);
     localBusinessTrainingPairDTO.setLeftName("leftName");
     localBusinessTrainingPairDTO.setRightId(2);
     localBusinessTrainingPairDTO.setRightName("rightName");

     localBusinessTrainingPairsDTO.add(localBusinessTrainingPairDTO);

     //Creating HeaderColumnNameMappingStrategy
     HeaderColumnNameMappingStrategy<LocalBusinessTrainingPairDTO> mappingStrategy = new HeaderColumnNameMappingStrategy<>();
     mappingStrategy.setType(LocalBusinessTrainingPairDTO.class);
     //Setting predefined order using String comparator
     mappingStrategy.setColumnOrderOnWrite(new OrderedComparatorIgnoringCase(LocalBusinessTrainingPairDTO.FIELDS_ORDER));
     String csv = convertToCsv(localBusinessTrainingPairsDTO, mappingStrategy);
     System.out.println(csv);
}
publicstaticvoidmain(字符串[]args)引发异常{
列出localBusinessTrainingPairsDTO=new ArrayList();
LocalBusinessTrainingPairDTO LocalBusinessTrainingPairDTO=新建LocalBusinessTrainingPairDTO();
localBusinessTrainingPairDTO.setLeftId(1);
localBusinessTrainingPairDTO.setLeftName(“leftName”);
localBusinessTrainingPairDTO.setRightId(2);
localBusinessTra
public class ColumnAndNameMappingStrategy<T> extends ColumnPositionMappingStrategy<T> {

@Override
public String[] generateHeader(T bean) throws CsvRequiredFieldEmptyException {

    super.setColumnMapping(new String[ getAnnotatedFields(bean)]);
    final int numColumns = getAnnotatedFields(bean);
    final int totalFieldNum = findMaxFieldIndex();
    if (!isAnnotationDriven() || numColumns == -1) {
        return super.generateHeader(bean);
    }

    String[] header = new String[numColumns];

    BeanField<T> beanField;
    for (int i = 0; i <= totalFieldNum; i++) {
        beanField = findField(i);
        if (isFieldAnnotated(beanField.getField())) {
            String columnHeaderName = extractHeaderName(beanField);
            header[i] = columnHeaderName;
        }
    }
    return header;
}

private int getAnnotatedFields(T bean) {
    return (int) Arrays.stream(FieldUtils.getAllFields(bean.getClass()))
            .filter(this::isFieldAnnotated)
            .count();
}

private boolean isFieldAnnotated(Field f) {
    return f.isAnnotationPresent(CsvBindByName.class) || f.isAnnotationPresent(CsvCustomBindByName.class);
}

private String extractHeaderName(final BeanField beanField) {
    if (beanField == null || beanField.getField() == null) {
        return StringUtils.EMPTY;
    }

    Field field = beanField.getField();

    if (field.getDeclaredAnnotationsByType(CsvBindByName.class).length != 0) {
        final CsvBindByName bindByNameAnnotation = field.getDeclaredAnnotationsByType(CsvBindByName.class)[0];
        return bindByNameAnnotation.column();
    }

    if (field.getDeclaredAnnotationsByType(CsvCustomBindByName.class).length != 0) {
        final CsvCustomBindByName bindByNameAnnotation = field.getDeclaredAnnotationsByType(CsvCustomBindByName.class)[0];
        return bindByNameAnnotation.column();
    }

    return StringUtils.EMPTY;
}
HeaderColumnNameMappingStrategy
mappingStrategy.setColumnOrderOnWrite(Comparator<String> writeOrder)
import com.opencsv.CSVWriter;
import com.opencsv.bean.*;
import org.springframework.web.multipart.MultipartFile;

import java.io.*;
import java.util.List;

public class CsvUtils {
    private CsvUtils() {
    }

    public static <T> String convertToCsv(List<T> entitiesList, MappingStrategy<T> mappingStrategy) throws Exception {
        try (Writer writer = new StringWriter()) {
            StatefulBeanToCsv<T> beanToCsv = new StatefulBeanToCsvBuilder<T>(writer)
                    .withMappingStrategy(mappingStrategy)
                    .withQuotechar(CSVWriter.NO_QUOTE_CHARACTER)
                    .build();
            beanToCsv.write(entitiesList);
            return writer.toString();
        }
    }

    @SuppressWarnings("unchecked")
    public static <T> List<T> convertFromCsv(MultipartFile file, Class clazz) throws IOException {
        try (Reader reader = new BufferedReader(new InputStreamReader(file.getInputStream()))) {
            CsvToBean<T> csvToBean = new CsvToBeanBuilder<T>(reader).withType(clazz).build();
            return csvToBean.parse();
        }
    }
}
public class LocalBusinessTrainingPairDTO {
    //this is used for CSV columns ordering on exporting LocalBusinessTrainingPairs
    public static final String[] FIELDS_ORDER = {"leftId", "leftName", "rightId", "rightName"};

    @CsvBindByName(column = "leftId")
    private int leftId;

    @CsvBindByName(column = "leftName")
    private String leftName;

    @CsvBindByName(column = "rightId")
    private int rightId;

    @CsvBindByName(column = "rightName")
    private String rightName;
    // getters/setters omitted, do not forget to add them
}
public class OrderedComparatorIgnoringCase implements Comparator<String> {
    private List<String> predefinedOrder;

    public OrderedComparatorIgnoringCase(String[] predefinedOrder) {
        this.predefinedOrder = new ArrayList<>();
        for (String item : predefinedOrder) {
            this.predefinedOrder.add(item.toLowerCase());
        }
    }

    @Override
    public int compare(String o1, String o2) {
        return predefinedOrder.indexOf(o1.toLowerCase()) - predefinedOrder.indexOf(o2.toLowerCase());
    }
}
public static void main(String[] args) throws Exception {
     List<LocalBusinessTrainingPairDTO> localBusinessTrainingPairsDTO = new ArrayList<>();
     LocalBusinessTrainingPairDTO localBusinessTrainingPairDTO = new LocalBusinessTrainingPairDTO();
     localBusinessTrainingPairDTO.setLeftId(1);
     localBusinessTrainingPairDTO.setLeftName("leftName");
     localBusinessTrainingPairDTO.setRightId(2);
     localBusinessTrainingPairDTO.setRightName("rightName");

     localBusinessTrainingPairsDTO.add(localBusinessTrainingPairDTO);

     //Creating HeaderColumnNameMappingStrategy
     HeaderColumnNameMappingStrategy<LocalBusinessTrainingPairDTO> mappingStrategy = new HeaderColumnNameMappingStrategy<>();
     mappingStrategy.setType(LocalBusinessTrainingPairDTO.class);
     //Setting predefined order using String comparator
     mappingStrategy.setColumnOrderOnWrite(new OrderedComparatorIgnoringCase(LocalBusinessTrainingPairDTO.FIELDS_ORDER));
     String csv = convertToCsv(localBusinessTrainingPairsDTO, mappingStrategy);
     System.out.println(csv);
}
public static void main(String[] args) throws Exception {
    //omitted code from writing
    String csv = convertToCsv(localBusinessTrainingPairsDTO, mappingStrategy);

    //Exported CSV should be compatible for further import
    File temp = File.createTempFile("tempTrainingPairs", ".csv");
    temp.deleteOnExit();
    BufferedWriter bw = new BufferedWriter(new FileWriter(temp));
    bw.write(csv);
    bw.close();
    MultipartFile multipartFile = new MockMultipartFile("tempTrainingPairs.csv", new FileInputStream(temp));

    List<LocalBusinessTrainingPairDTO> localBusinessTrainingPairDTOList = convertFromCsv(multipartFile, LocalBusinessTrainingPairDTO.class);
}
private static class CustomMappingStrategy<T> extends ColumnPositionMappingStrategy<T> {

    String[] header;

    public CustomMappingStrategy(String[] cols) {
        header = cols;
    }

    @Override
    public String[] generateHeader(T bean) throws CsvRequiredFieldEmptyException {
        return header;
    }
}
String[] columns = new String[]{"Name", "Age", "Company", "Salary"};
        CustomMappingStrategy<Employee> mappingStrategy = new CustomMappingStrategy<Employee>(columns);
"COLUMN 1","COLUMN 2","COLUMN 3",...
"value 1a","value 2a","value 3a",...
"value 1b","value 2b","value 3b",...
/**
 * Custom OpenCSV [ColumnPositionMappingStrategy] that allows for a header line to be generated from a target CSV
 * bean model class using the following annotations when present:
 * * [CsvBindByName]
 * * [CsvCustomBindByName]
 */
class CustomMappingStrategy<T>(private val beanType: Class<T>) : ColumnPositionMappingStrategy<T>() {
    init {
        setType(beanType)
        setColumnMapping(*getAnnotatedFields().map { it.extractHeaderName() }.toTypedArray())
    }

    override fun generateHeader(bean: T): Array<String> = columnMapping

    private fun getAnnotatedFields() = beanType.declaredFields.filter { it.isAnnotatedByName() }.toList()

    private fun Field.isAnnotatedByName() = isAnnotationPresent(CsvBindByName::class.java) || isAnnotationPresent(CsvCustomBindByName::class.java)

    private fun Field.extractHeaderName() =
        getAnnotation(CsvBindByName::class.java)?.column ?: getAnnotation(CsvCustomBindByName::class.java)?.column ?: EMPTY
}
private fun csvBuilder(writer: Writer) =
    StatefulBeanToCsvBuilder<MappingsBean>(writer)
        .withSeparator(ICSVWriter.DEFAULT_SEPARATOR)
        .withMappingStrategy(CustomMappingStrategy(MappingsBean::class.java))
        .withApplyQuotesToAll(false)
        .build()

// Kotlin try-with-resources construct
PrintWriter(File("$reportOutputDir/$REPORT_FILENAME")).use { writer ->
    csvBuilder(writer).write(makeFinalMappingBeanList())
}
data class MappingsBean(
    @field:CsvBindByName(column = "TradeID")
    @field:CsvBindByPosition(position = 0, required = true)
    private val tradeId: String,

    @field:CsvBindByName(column = "GWML GUID", required = true)
    @field:CsvBindByPosition(position = 1)
    private val gwmlGUID: String,

    @field:CsvBindByName(column = "MXML GUID", required = true)
    @field:CsvBindByPosition(position = 2)
    private val mxmlGUID: String,

    @field:CsvBindByName(column = "GWML File")
    @field:CsvBindByPosition(position = 3)
    private val gwmlFile: String? = null,

    @field:CsvBindByName(column = "MxML File")
    @field:CsvBindByPosition(position = 4)
    private val mxmlFile: String? = null,

    @field:CsvBindByName(column = "MxML Counterparty")
    @field:CsvBindByPosition(position = 5)
    private val mxmlCounterParty: String? = null,

    @field:CsvBindByName(column = "GWML Counterparty")
    @field:CsvBindByPosition(position = 6)
    private val gwmlCounterParty: String? = null
)
public class CustomMappingStrategy<T> extends ColumnPositionMappingStrategy<T> {
   @Override
   public String[] generateHeader(T bean) throws CsvRequiredFieldEmptyException {

       super.setColumnMapping(new String[ FieldUtils.getAllFields(bean.getClass()).length]);
       final int numColumns = findMaxFieldIndex();
       if (!isAnnotationDriven() || numColumns == -1) {
           return super.generateHeader(bean);
       }

       String[] header = new String[numColumns + 1];

       BeanField<T> beanField;
       for (int i = 0; i <= numColumns; i++) {
           beanField = findField(i);
           String columnHeaderName = extractHeaderName(beanField);
           header[i] = columnHeaderName;
       }
       return header;
   }

   private String extractHeaderName(final BeanField<T> beanField) {
       if (beanField == null || beanField.getField() == null
               || beanField.getField().getDeclaredAnnotationsByType(CsvBindByName.class).length == 0) {
           return StringUtils.EMPTY;
       }

       final CsvBindByName bindByNameAnnotation = beanField.getField()
               .getDeclaredAnnotationsByType(CsvBindByName.class)[0];
       return bindByNameAnnotation.column();
   }
}
 public class Customer{

     @CsvBindByPosition(position=1)
     @CsvBindByName(column="CUSTOMER", required = true)
     private String customer;
}
 List<T> data = getEmployeeRecord();
CustomMappingStrategy custom = new CustomMappingStrategy();
custom.setType(Employee.class);
StatefulBeanToCsv<T> writer = new StatefulBeanToCsvBuilder<T>(response.getWriter())
                .withQuotechar(CSVWriter.NO_QUOTE_CHARACTER)
                .withSeparator('|')
                .withOrderedResults(false)
                .withMappingStrategy(custom)
                .build();
        writer.write(reportData);
public class MappingBean {
     @CsvBindByName(column = "column_a")
     private String columnA;
     @CsvBindByName(column = "column_b")
     private String columnB;
     @CsvBindByName(column = "column_c")
     private String columnC;

     // getters and setters
}
import org.apache.commons.collections4.comparators.FixedOrderComparator;
var mappingStrategy = new HeaderColumnNameMappingStrategy<MappingBean>();
mappingStrategy.setType(MappingBean.class);        
mappingStrategy.setColumnOrderOnWrite(new FixedOrderComparator<>("COLUMN_C", "COLUMN_B", "COLUMN_A"));

var sbc = new StatefulBeanToCsvBuilder<MappingBean>(writer)
      .withMappingStrategy(mappingStrategy)
      .build();
import com.opencsv.bean.BeanField;
import com.opencsv.bean.ColumnPositionMappingStrategy;
import com.opencsv.bean.CsvBindByName;
import com.opencsv.exceptions.CsvRequiredFieldEmptyException;
import org.apache.commons.lang3.StringUtils;

class CustomMappingStrategy<T> extends ColumnPositionMappingStrategy<T> {
    @Override
    public String[] generateHeader(T bean) throws CsvRequiredFieldEmptyException {
        final int numColumns = getFieldMap().values().size();
        super.generateHeader(bean);

        String[] header = new String[numColumns];

        BeanField beanField;
        for (int i = 0; i < numColumns; i++) {
            beanField = findField(i);
            String columnHeaderName = extractHeaderName(beanField);
            header[i] = columnHeaderName;
        }
        return header;
    }

    private String extractHeaderName(final BeanField beanField) {
        if (beanField == null || beanField.getField() == null || beanField.getField().getDeclaredAnnotationsByType(
                CsvBindByName.class).length == 0) {
            return StringUtils.EMPTY;
        }

        final CsvBindByName bindByNameAnnotation = beanField.getField().getDeclaredAnnotationsByType(CsvBindByName.class)[0];
        return bindByNameAnnotation.column();
    }
}
@CsvBindByName(column = "id")
@CsvBindByPosition(position = 0)
private Long id;
@CsvBindByName(column = "name")
@CsvBindByPosition(position = 1)
private String name;
public static <T extends AbstractCsv> String createCsv(List<T> data, Class<T> beanClazz) {
    CustomMappingStrategy<T> mappingStrategy = new CustomMappingStrategy<T>();
    mappingStrategy.setType(beanClazz);

    StringWriter writer = new StringWriter();
    String csv = "";
    try {
        StatefulBeanToCsv sbc = new StatefulBeanToCsvBuilder(writer)
                .withSeparator(';')
                .withMappingStrategy(mappingStrategy)
                .build();
        sbc.write(data);
        csv = writer.toString();
    } catch (CsvRequiredFieldEmptyException e) {
        // TODO add some logging...
    } catch (CsvDataTypeMismatchException e) {
        // TODO add some logging...
    } finally {
        try {
            writer.close();
        } catch (IOException e) {
        }
    }
    return csv;
}
HeaderColumnNameMappingStrategy<MyCsvBean> mappingStrategy = new HeaderColumnNameMappingStrategy<>();
    mappingStrategy.setType(MyCsvBean.class);
    mappingStrategy.setColumnOrderOnWrite(new ClassFieldOrderComparator(MyCsvBean.class));
private class ClassFieldOrderComparator implements Comparator<String> {

    List<String> fieldNamesInOrderWithinClass;

    public ClassFieldOrderComparator(Class<?> clazz) {
        fieldNamesInOrderWithinClass = Arrays.stream(clazz.getDeclaredFields())
                .filter(field -> field.getAnnotation(CsvBindByName.class) != null)
              // Handle order by your custom annotation here
              //.sorted((field1, field2) -> {
              //   int field1Order = field1.getAnnotation(YourCustomOrderAnnotation.class).getOrder();
              //   int field2Order = field2.getAnnotation(YourCustomOrderAnnotation.class).getOrder();
              //   return Integer.compare(field1Order, field2Order);
              //})
                .map(field -> field.getName().toUpperCase())
                .collect(Collectors.toList());
    }

    @Override
    public int compare(String o1, String o2) {
        int fieldIndexo1 = fieldNamesInOrderWithinClass.indexOf(o1);
        int fieldIndexo2 = fieldNamesInOrderWithinClass.indexOf(o2);
        return Integer.compare(fieldIndexo1, fieldIndexo2);
    }
}
            String[] csvHeader= {"Id#","Shiv Record Number","Shiv Vendor Id","Shiva Tech Id#","finShortNameTb","finVenName1Tb","finVenName2Tb"};

            CustomMappingStrategy<FinVendor> mappingStrategy = new CustomMappingStrategy(csvHeader);//csvHeader as per custom header irrespective of pojo field name
            mappingStrategy.setType(FinVendor.class);
            mappingStrategy.setColumnMapping(fields);//pojo mapping fields


            StatefulBeanToCsv<FinVendor> beanToCsv = new StatefulBeanToCsvBuilder<FinVendor>(writer).withQuotechar(CSVWriter.NO_QUOTE_CHARACTER).withMappingStrategy(mappingStrategy).build();
            beanToCsv.write(readVendors);
                    String[] header;

                    public CustomMappingStrategy(String[] cols) {

                            header = cols;
                    }

                    @Override
                    public String[] generateHeader(T bean) throws CsvRequiredFieldEmptyException {
                        super.generateHeader(bean);
                            return header;
                    }
                    }
Id#     Shiv Record Number      Shiv Vendor Id   Fin Tech Id#      finShortNameTb  finVenName1Tb   finVenName2Tb   finVenDefaultLocTb
1       VEN00053                678             33316025986        THE ssOHIO S_2  THE UNIVERSITY     CHK         Test
2       VEN02277                1217            3044374205         Fe3 MECHA_1     FR3INC             EFT-1
3       VEN03118                1310            30234484121        PE333PECTUS_1   PER332CTUS AR      EFT-1       Test
import com.opencsv.bean.BeanField;
import com.opencsv.bean.ColumnPositionMappingStrategy;
import com.opencsv.bean.CsvBindByName;
import com.opencsv.exceptions.CsvRequiredFieldEmptyException;

/**
 * @param <T>
 */
class CustomMappingStrategy<T> extends ColumnPositionMappingStrategy<T> {
    /*
     * (non-Javadoc)
     * 
     * @see com.opencsv.bean.ColumnPositionMappingStrategy#generateHeader(java.lang.
     * Object)
     */
    @Override
    public String[] generateHeader(T bean) throws CsvRequiredFieldEmptyException {
        final int numColumns = getFieldMap().values().size();
        if (numColumns == -1) {
            return super.generateHeader(bean);
        }

        String[] header = new String[numColumns];
        super.setColumnMapping(header);

        BeanField<T, Integer> beanField;
        for (int i = 0; i < numColumns; i++) {
            beanField = findField(i);
            String columnHeaderName = beanField.getField().getDeclaredAnnotation(CsvBindByName.class).column();
            header[i] = columnHeaderName;
        }
        return header;
    }
}
CustomMappingStrategy<ScanReport> strategy = new CustomMappingStrategy<>();
            strategy.setType(ScanReport.class);

// Write a bean to csv file.
StatefulBeanToCsv<ScanReport> beanToCsv = new StatefulBeanToCsvBuilder<ScanReport>(writer)
                    .withMappingStrategy(strategy).build();
beanToCsv.write(beanList);
public class CustomBeanToCSVMappingStrategy<T> extends ColumnPositionMappingStrategy<T> {

    @Override
    public String[] generateHeader(T bean) throws CsvRequiredFieldEmptyException {

        String[] headersAsPerFieldName = getFieldMap().generateHeader(bean); // header name based on field name

        String[] header = new String[headersAsPerFieldName.length];

        for (int i = 0; i <= headersAsPerFieldName.length - 1; i++) {

            BeanField beanField = findField(i);

            String columnHeaderName = extractHeaderName(beanField); // header name based on @CsvBindByName annotation

            if (columnHeaderName.isEmpty()) // No @CsvBindByName is present
                columnHeaderName = headersAsPerFieldName[i]; // defaults to header name based on field name

            header[i] = columnHeaderName;
        }

        headerIndex.initializeHeaderIndex(header);

        return header;
    }

    private String extractHeaderName(final BeanField beanField) {
        if (beanField == null || beanField.getField() == null || beanField.getField().getDeclaredAnnotationsByType(CsvBindByName.class).length == 0) {
            return StringUtils.EMPTY;
        }

        final CsvBindByName bindByNameAnnotation = beanField.getField().getDeclaredAnnotationsByType(CsvBindByName.class)[0];
        return bindByNameAnnotation.column();
    }
}
@Getter @Setter @ToString
public class Pojo {

    @CsvBindByName(column="Voucher Series") // header: "Voucher Series"
    @CsvBindByPosition(position=0)
    private String voucherSeries;

    @CsvBindByPosition(position=1) // header: "salePurchaseType"
    private String salePurchaseType;
}
CustomBeanToCSVMappingStrategy<Pojo> mappingStrategy = new CustomBeanToCSVMappingStrategy<>();
            mappingStrategy.setType(Pojo.class);

StatefulBeanToCsv<Pojo> beanToCsv = new StatefulBeanToCsvBuilder<Pojo>(writer)
                    .withSeparator(CSVWriter.DEFAULT_SEPARATOR)
                    .withMappingStrategy(mappingStrategy)
                    .build();

beanToCsv.write(pojoList);
class CustomMappingStrategy<T> extends ColumnPositionMappingStrategy<T> {
private static final String[] HEADER = new String[]{"TradeID", "GWML GUID", "MXML GUID", "GWML File", "MxML File", "MxML Counterparty", "GWML Counterparty"};

@Override
public String[] generateHeader() {
    super.generateHeader(bean); // without this the file contains ONLY headers
    return HEADER;
}
@Target(ElementType.FIELD)
@Inherited
@Retention(RetentionPolicy.RUNTIME)
public @interface CsvPosition {

  int position();
}

public class CustomMappingStrategy<T> extends HeaderColumnNameMappingStrategy<T> {

  private final Field[] fields;

  public CustomMappingStrategy(Class<T> clazz) {
    fields = clazz.getDeclaredFields();
    Arrays.sort(fields, (f1, f2) -> {
      CsvPosition position1 = f1.getAnnotation(CsvPosition.class);
      CsvPosition position2 = f2.getAnnotation(CsvPosition.class);
      return Integer.compare(position1.position(), position2.position());
    });
  }

  @Override
  public String[] generateHeader(T bean) throws CsvRequiredFieldEmptyException {
    String[] header = new String[fields.length];
    for (Field f : fields) {
      CsvPosition position = f.getAnnotation(CsvPosition.class);
      header[position.position() - 1] = getName(f);
    }
    headerIndex.initializeHeaderIndex(header);
    return header;
  }

  private String getName(Field f) {
    CsvBindByName csvBindByName = f.getAnnotation(CsvBindByName.class);
    CsvCustomBindByName csvCustomBindByName = f.getAnnotation(CsvCustomBindByName.class);
    return csvCustomBindByName != null
      ? csvCustomBindByName.column() == null || csvCustomBindByName.column().isEmpty() ? f.getName() : csvCustomBindByName.column()
      : csvBindByName.column() == null || csvBindByName.column().isEmpty() ? f.getName() : csvBindByName.column();
  }

}
CustomMappingStrategy<Record> mappingStrategy = new CustomMappingStrategy<>(Record.class);
mappingStrategy.setType(Record.class);
StatefulBeanToCsv beanToCsv = new StatefulBeanToCsvBuilder(writer)
.withApplyQuotesToAll(false)
.withOrderedResults(true)
.withMappingStrategy(mappingStrategy)
.build();