Search code examples
javafirebasespring-bootopencsv

Spring Boot opencsv


I am trying to use opencsv to parse a csv file like this:

name,purchase,date
TEST,TEST,2020-10-20T00:37:53.562000000Z
TEST,TEST,2020-10-20T00:37:53.562000000Z

I am trying to add the parsed data to a firebase database following this tutorial: https://attacomsian.com/blog/spring-boot-upload-parse-csv-file. This is my class for the data:

public class Records {
  @CsvBindByName
  private String name;
  @CsvBindByName
  private String purchase;
  @CsvBindByName
  private Timestamp date;

  // get and setters left out for brevity pls comment if needed
}

When I parse the file I get this error:

Exception in thread "pool-6-thread-2" Exception in thread "pool-6-thread-1" Exception in thread "pool-6-thread-4" Exception in thread "pool-6-thread-3" java.lang.RuntimeException: com.opencsv.exceptions.CsvDataTypeMismatchException: Conversion of 2022-10-20T00:37:53.562000000Z to com.google.cloud.Timestamp failed.
    at com.opencsv.bean.concurrent.ProcessCsvLine.run(ProcessCsvLine.java:99)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
    at java.lang.Thread.run(Thread.java:748)
Caused by: com.opencsv.exceptions.CsvDataTypeMismatchException: Conversion of 2022-10-20T00:37:53.562000000Z to com.google.cloud.Timestamp failed.
    at com.opencsv.bean.ConverterPrimitiveTypes.convertToRead(ConverterPrimitiveTypes.java:128)
    at com.opencsv.bean.BeanFieldSingleValue.convert(BeanFieldSingleValue.java:98)
    at com.opencsv.bean.AbstractBeanField.setFieldValue(AbstractBeanField.java:180)
    at com.opencsv.bean.AbstractMappingStrategy.setFieldValue(AbstractMappingStrategy.java:581)
    at com.opencsv.bean.AbstractMappingStrategy.populateNewBean(AbstractMappingStrategy.java:328)
    at com.opencsv.bean.concurrent.ProcessCsvLine.processLine(ProcessCsvLine.java:128)
    at com.opencsv.bean.concurrent.ProcessCsvLine.run(ProcessCsvLine.java:83)
    ... 3 more
Caused by: org.apache.commons.beanutils.ConversionException: Can't convert value '2022-10-20T00:37:53.562000000Z' to type class com.google.cloud.Timestamp
    at org.apache.commons.beanutils.converters.AbstractConverter.conversionException(AbstractConverter.java:474)
    at org.apache.commons.beanutils.converters.StringConverter.convertToType(StringConverter.java:96)
    at org.apache.commons.beanutils.converters.AbstractConverter.convert(AbstractConverter.java:169)
    at org.apache.commons.beanutils.converters.ConverterFacade.convert(ConverterFacade.java:61)
    at org.apache.commons.beanutils.ConvertUtilsBean.convert(ConvertUtilsBean.java:491)
    at com.opencsv.bean.ConverterPrimitiveTypes.convertToRead(ConverterPrimitiveTypes.java:118)
    ... 9 more

How can i fix this error? Do I need to change the format of the date column? I copied the date format from a record in the database so that format is how it should be stored in the database


Solution

  • I changed the csv format to:

    name,purchase,date
    TEST,TEST,2018-09-16T08:00:00
    TEST,TEST,2018-09-16T08:00:00
    

    I modified the class that binds to the csv to look like this:

    public class CsvRecords {
      @CsvBindByName
      private String name;
      @CsvBindByName
      private String purchase;
      @CsvBindByName
      private String date;
    
      // get and setters left out for brevity pls comment if needed
    }
    

    The POJO class for the data in db:

    public class Records {
      private String name;
      private String purchase;
      private Timestamp date;
    
      // get and setters left out for brevity pls comment if needed
    }
    

    When uploading in the controller class I then convert the string to LocalDateTime and then again to Timestamp like this:

    @PostMapping("/upload-csv-file")
        public String uploadCSVFile(@RequestParam("file") MultipartFile file, Model model) {
    
            // validate file
            if (file.isEmpty()) {
                model.addAttribute("message", "Please select a CSV file to upload.");
                model.addAttribute("status", false);
            } else {
    
                // parse CSV file to create a list of `User` objects
                try (Reader reader = new BufferedReader(new InputStreamReader(file.getInputStream()))) {
    
                    // create csv bean reader
                    CsvToBean<Records> csvToBean = new CsvToBeanBuilder(reader)
                            .withType(Records.class)
                            .withIgnoreLeadingWhiteSpace(true)
                            .build();
    
                    // convert `CsvToBean` object to list of records
                    List<Records> records = csvToBean.parse();
    
                    // save users in DB?
                    for(int i = 0; i<records.size(); i++){
                       LocalDateTime localDateTime = LocalDateTime.parse(records.get(i).getDate);
                       Timestamp timestamp = Timestamp.valueOf(localDateTime);
                       Records rec = new Records(records.get(i).getName(), records.get(i).getPurchase(), timestamp)
                       firebaseServices.saveDetails(rec);
                     }
                } catch (Exception ex) {
                    model.addAttribute("message", "An error occurred while processing the CSV file.");
                    model.addAttribute("status", false);
                }
            }
    
            return "file-upload-status";
        }
    

    For details on the implementation of the firebaseServices class (saveDetails method) I used this tutorial