Search code examples
javaopencsv

Converting string into pojo class using opencv throwing exception


I need to convert my http response into Model and my response is plain csv format:

try {
    StringReader stringReader = new StringReader(string);
    CSVReader csvReader = new CSVReaderBuilder(stringReader).build();

    CsvToBean<SampleModel> csvToBean = new CsvToBeanBuilder<SampleModel>(csvReader)
            .withType(SampleModel.class)
            .withIgnoreLeadingWhiteSpace(true)
            .build();
    arrayList =(ArrayList<SampleModel>)csvToBean.parse();
} catch (Exception e) {
    System.out.println(e.getMessage());
}

It's throwing me exception:

Error capturing CSV header!

The string looks like this:

Name, Date
Alex, 2012-10-30
Borhan, 2012-11-05

I have been following the work from here: https://sourceforge.net/p/opencsv/bugs/196/#ee18


Solution

  • If you have one or more constructors with arguments, create a no-arg constructor explicitly in the bean class. If you do not have one or more constructors with arguments, you do not need to create a no-arg constructor explicitly.

    SampleModel.java:

    import com.opencsv.bean.CsvBindByName;
    
    public class SampleModel {
        @CsvBindByName(column = "Name")
        private String name;
    
        @CsvBindByName(column = "Date")
        private String date;
    
        public SampleModel() {
            // Empty
        }
    
        public SampleModel(String name, String date) {
            this.name = name;
            this.date = date;
        }
    
        public void setName(String name) {
            this.name = name;
        }
    
        public void setDate(String date) {
            this.date = date;
        }
    
        @Override
        public String toString() {
            return "{" + name + ", " + date + "}";
        }
    }
    

    As you can see, I have a two-args constructor and therefore I need to provide a no-arg constructor explicitly. If you remove the no-arg constructor and run Main.java (given below), it will fail at runtime.

    However, the following definition of the bean does not require an explicit no-arg constructor. You can verify it by running Main.java again with this definition.

    import com.opencsv.bean.CsvBindByName;
    
    public class SampleModel {
        @CsvBindByName(column = "Name")
        private String name;
    
        @CsvBindByName(column = "Date")
        private String date;
    
        public void setName(String name) {
            this.name = name;
        }
    
        public void setDate(String date) {
            this.date = date;
        }
    
        @Override
        public String toString() {
            return "{" + name + ", " + date + "}";
        }
    }
    

    Main.java:

    import java.io.StringReader;
    import java.util.List;
    
    import com.opencsv.CSVReader;
    import com.opencsv.CSVReaderBuilder;
    import com.opencsv.bean.CsvToBeanBuilder;
    
    public class Main {
        public static void main(String[] args) {
            String string = "Name, Date\n" + 
                            "Alex, 2012-10-30\n" + 
                            "Borhan, 2012-11-05";
    
            try {
                StringReader stringReader = new StringReader(string);
                CSVReader csvReader = new CSVReaderBuilder(stringReader).build();
                List<SampleModel> arrayList= new CsvToBeanBuilder<SampleModel>(csvReader)
                                        .withType(SampleModel.class)
                                        .withIgnoreLeadingWhiteSpace(true)
                                        .withSkipLines(1)// Skip the header line
                                        .build()
                                        .parse();
                System.out.println(arrayList);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }
    

    Output:

    [{Alex,  2012-10-30}, {Borhan,  2012-11-05}]
    

    Original answer:

    A workaround is to create an instance of the bean out of each record you read from the CSV and add the instance to the List as shown below:

    List<SampleModel> arrayList = new ArrayList<>();
    String[] nextRecord;
    CSVReader csvReader = new CSVReaderBuilder(stringReader)
                            .withSkipLines(1)// Skip the header line
                            .build();
    
    while ((nextRecord = csvReader.readNext()) != null) {
        arrayList.add(new SampleModel(nextRecord[0], nextRecord[1]));
    }