Warm tip: This article is reproduced from serverfault.com, please click

Why opencsv capitalizing csv headers while writing to file

发布于 2019-05-16 12:02:10

While writing Beans to CSV file by using OpenCSV 4.6, all the headers are changing to uppercase. Eventhough bean has @CsvBindByName annotation it is changing to uppercase.

Java Bean:

public class ProjectInfo implements Serializable {

    @CsvBindByName(column = "ProjectName",required = true)
    private String projectName;

    @CsvBindByName(column = "ProjectCode",required = true)
    private String projectCode;

    @CsvBindByName(column = "Visibility",required = true)
    private String visibility;
    //setters and getters
}

Main method

public static void main(String[] args) throws IOException {
    Collection<Serializable> projectInfos = getProjectsInfo();
    try(BufferedWriter writer = new BufferedWriter(new FileWriter("test.csv"))){
        StatefulBeanToCsvBuilder builder = new StatefulBeanToCsvBuilder(writer);
        StatefulBeanToCsv beanWriter = builder
                    .withSeparator(';')
                    .build();
        try {
              beanWriter.write(projectInfos.iterator());
              writer.flush();

         } catch (CsvDataTypeMismatchException | CsvRequiredFieldEmptyException  e) {
                throw new RuntimeException("Failed to download admin file");
            }
        }

    }

Expected Result:

"ProjectCode";"ProjectName";"Visibility"
"ANY";"Country DU";"1"
"STD";"Standard";"1"
"TST";"Test";"1"
"CMM";"CMMTest";"1"

Acutal Result:

"PROJECTCODE";"PROJECTNAME";"VISIBILITY"
"ANY";"Country DU";"1"
"STD";"Standard";"1"
"TST";"Test";"1"
"CMM";"CMMTest";"1"

I don't have option to use ColumnMappingStrategy because I have to build this method as a generic solution. can anyone suggest me how to write the headers as it is?

Questioner
prasadg
Viewed
0
Sascha 2021-08-28 16:34:57

It happens, because the code in HeaderColumnNameMappingStrategy uses toUpperCase() for storing and retrieving the field names.

You could use the HeaderColumnNameTranslateMappingStrategy instead and create the mapping by reflection.

    
    public class AnnotationStrategy extends HeaderColumnNameTranslateMappingStrategy
    {
        public AnnotationStrategy(Class<?> clazz)
        {
            Map<String,String> map=new HashMap<>();
            //To prevent the column sorting
            List<String> originalFieldOrder=new ArrayList<>();
            for(Field field:clazz.getDeclaredFields())
            {
                CsvBindByName annotation = field.getAnnotation(CsvBindByName.class);
                if(annotation!=null)
                {
                    map.put(annotation.column(),annotation.column());
                    originalFieldOrder.add(annotation.column());
                }
            }
            setType(clazz);
            setColumnMapping(map);
            //Order the columns as they were created
            setColumnOrderOnWrite((a,b) -> Integer.compare(originalFieldOrder.indexOf(a), originalFieldOrder.indexOf(b)));
        }
        
        @Override
        public String[] generateHeader(Object bean) throws CsvRequiredFieldEmptyException
        {
            String[] result=super.generateHeader(bean);
            for(int i=0;i<result.length;i++)
            {
                result[i]=getColumnName(i);
            }
            return result;
        }
    }

And, assuming that there is only one class of items (and always at least one item), the creation of beanWriter has to be expanded:

StatefulBeanToCsv beanWriter = builder.withSeparator(';')
    .withMappingStrategy(new AnnotationStrategy(projectInfos.iterator().next().getClass()))
    .build();