Search code examples
javakotlinopencsv

Opencsv validating CSV header with bean headers


I have a class like :

data class BeanClass (
        @CsvBindByName(column = "Id")
        val id: Long = -1,
)

and using this to convert it to a list of IDs

val recommendationUpdateList = CSVUtils.convertToBean(file, BeanClass::class.java)

CSVUtils.convertToBean looks like this :

public static <T> List<T> convertToBean(File file, Class<T> bean) throws IOException {
        List<T> csvData = null;
        try (Reader reader = new FileReader(file)) {
            HeaderColumnNameMappingStrategy<T> strategy =
                    new HeaderColumnNameMappingStrategy<T>();
            strategy.setType(bean);
            CsvToBean<T> cb = new CsvToBeanBuilder<T>(reader)
                    .withType(bean)
                    .withFieldAsNull(CSVReaderNullFieldIndicator.BOTH)
                    .withMappingStrategy(strategy)
                    .build();
            csvData = cb.parse();
        }
        return csvData;
    }

Now when I upload a CSV like this, it's working fine

Id
2

HOWEVER, I want it throw an error when I use the following CSV (notice the name of CSV header has changed)

Kd
2

Please suggest a way ahead where header of csv can be validated against the bean column headers. What it is doing currently is picking default value -1, also in my usecase I can't verify on basis of default value.


Solution

  • Found a simple solution :

    public static <T> List<T> convertToBean(File file, Class<T> bean, Boolean validate) throws IOException, CsvRequiredFieldEmptyException, RequestInvalidException {
            List<T> csvData = null;
    
            try(Reader reader = new FileReader(file)) {
                HeaderColumnNameMappingStrategy<T> strategy = new HeaderColumnNameMappingStrategy<T>();
                strategy.setType(bean);
    
                CsvToBean<T> cb = new CsvToBeanBuilder<T>(reader)
                        .withType(bean)
                        .withFieldAsNull(CSVReaderNullFieldIndicator.BOTH)
                        .withMappingStrategy(strategy)
                        .build();
                csvData = cb.parse();
    
                if(validate) {
                    String[] validHeaders = getHeaders(bean);
                    Set<String> validHeaderSet = new HashSet<>(Arrays.asList(validHeaders));
                    String[] actualHeaders = strategy.generateHeader((T) bean);
                    for(String header : actualHeaders) {
                        if(!validHeaderSet.contains(header.toUpperCase())) {
                            throw new Exception();
                        }
                    }
                }
            }
            return csvData;
        }
    
        public static <T> String[] getHeaders(Class<T> bean) throws CsvRequiredFieldEmptyException {
            HeaderColumnNameMappingStrategy<T> strategy = new HeaderColumnNameMappingStrategy<T>();
            strategy.setType(bean);
            return strategy.generateHeader((T) bean);
        }