NoSuchMethodException: java.time.LocalDateTime.<init>() reading CSV using Super CSV

Stuart Leyland-Cole picture Stuart Leyland-Cole · Dec 9, 2016 · Viewed 11.4k times · Source

I have written an entity that contains just a LocalDateTime to a CSV file using Super CSV's ICsvDozerBeanWriter and I am encountering an error when reading it back using a ICsvDozerBeanReader. I was able to successfully read and write a Date object but LocalDateTime isn't working.

I've added the super-csv-java8 dependency and the writing part appears to be working fine.

I've created a small demo application in this Github repo to replicate the problem. Run the main() method and the error will be output to the console.

This is the exception I'm getting:

2016-12-09 22:24:02.427 ERROR 50405 --- [           main] org.dozer.MappingProcessor               : Field mapping error -->
  MapId: null
  Type: null
  Source parent class: org.supercsv.io.dozer.CsvDozerBeanData
  Source field name: columns
  Source field type: class java.time.LocalDateTime
  Source field value: 2016-12-09T22:24:02.226
  Dest parent class: com.example.Entity
  Dest field name: dateTime
  Dest field type: java.time.LocalDateTime

org.dozer.MappingException: java.lang.NoSuchMethodException: java.time.LocalDateTime.<init>()
    at org.dozer.util.MappingUtils.throwMappingException(MappingUtils.java:82) ~[dozer-5.4.0.jar:na]
    at org.dozer.factory.ConstructionStrategies$ByConstructor.newInstance(ConstructionStrategies.java:261) ~[dozer-5.4.0.jar:na]
    at org.dozer.factory.ConstructionStrategies$ByConstructor.create(ConstructionStrategies.java:245) ~[dozer-5.4.0.jar:na]
    at org.dozer.factory.DestBeanCreator.create(DestBeanCreator.java:65) ~[dozer-5.4.0.jar:na]
    at org.dozer.MappingProcessor.mapCustomObject(MappingProcessor.java:489) [dozer-5.4.0.jar:na]
    at org.dozer.MappingProcessor.mapOrRecurseObject(MappingProcessor.java:446) [dozer-5.4.0.jar:na]
    at org.dozer.MappingProcessor.mapFromFieldMap(MappingProcessor.java:342) [dozer-5.4.0.jar:na]
    at org.dozer.MappingProcessor.mapField(MappingProcessor.java:288) [dozer-5.4.0.jar:na]
    at org.dozer.MappingProcessor.map(MappingProcessor.java:248) [dozer-5.4.0.jar:na]
    at org.dozer.MappingProcessor.map(MappingProcessor.java:197) [dozer-5.4.0.jar:na]
    at org.dozer.MappingProcessor.map(MappingProcessor.java:187) [dozer-5.4.0.jar:na]
    at org.dozer.MappingProcessor.map(MappingProcessor.java:124) [dozer-5.4.0.jar:na]
    at org.dozer.MappingProcessor.map(MappingProcessor.java:119) [dozer-5.4.0.jar:na]
    at org.dozer.DozerBeanMapper.map(DozerBeanMapper.java:120) [dozer-5.4.0.jar:na]
    at org.supercsv.io.dozer.CsvDozerBeanReader.readIntoBean(CsvDozerBeanReader.java:220) [super-csv-dozer-2.4.0.jar:na]
    at org.supercsv.io.dozer.CsvDozerBeanReader.read(CsvDozerBeanReader.java:160) [super-csv-dozer-2.4.0.jar:na]
    at com.example.DemoApplication.readEntities(DemoApplication.java:51) [classes/:na]
    at com.example.DemoApplication.main(DemoApplication.java:39) [classes/:na]
Caused by: java.lang.NoSuchMethodException: java.time.LocalDateTime.<init>()
    at java.lang.Class.getConstructor0(Class.java:3082) ~[na:1.8.0_66]
    at java.lang.Class.getDeclaredConstructor(Class.java:2178) ~[na:1.8.0_66]
    at org.dozer.factory.ConstructionStrategies$ByConstructor.newInstance(ConstructionStrategies.java:257) ~[dozer-5.4.0.jar:na]
    ... 16 common frames omitted

org.dozer.MappingException: java.lang.NoSuchMethodException: java.time.LocalDateTime.<init>()
    at org.dozer.util.MappingUtils.throwMappingException(MappingUtils.java:82)
    at org.dozer.factory.ConstructionStrategies$ByConstructor.newInstance(ConstructionStrategies.java:261)
    at org.dozer.factory.ConstructionStrategies$ByConstructor.create(ConstructionStrategies.java:245)
    at org.dozer.factory.DestBeanCreator.create(DestBeanCreator.java:65)
    at org.dozer.MappingProcessor.mapCustomObject(MappingProcessor.java:489)
    at org.dozer.MappingProcessor.mapOrRecurseObject(MappingProcessor.java:446)
    at org.dozer.MappingProcessor.mapFromFieldMap(MappingProcessor.java:342)
    at org.dozer.MappingProcessor.mapField(MappingProcessor.java:288)
    at org.dozer.MappingProcessor.map(MappingProcessor.java:248)
    at org.dozer.MappingProcessor.map(MappingProcessor.java:197)
    at org.dozer.MappingProcessor.map(MappingProcessor.java:187)
    at org.dozer.MappingProcessor.map(MappingProcessor.java:124)
    at org.dozer.MappingProcessor.map(MappingProcessor.java:119)
    at org.dozer.DozerBeanMapper.map(DozerBeanMapper.java:120)
    at org.supercsv.io.dozer.CsvDozerBeanReader.readIntoBean(CsvDozerBeanReader.java:220)
    at org.supercsv.io.dozer.CsvDozerBeanReader.read(CsvDozerBeanReader.java:160)
    at com.example.DemoApplication.readEntities(DemoApplication.java:51)
    at com.example.DemoApplication.main(DemoApplication.java:39)
Caused by: java.lang.NoSuchMethodException: java.time.LocalDateTime.<init>()
    at java.lang.Class.getConstructor0(Class.java:3082)
    at java.lang.Class.getDeclaredConstructor(Class.java:2178)
    at org.dozer.factory.ConstructionStrategies$ByConstructor.newInstance(ConstructionStrategies.java:257)

Ideally I'd like to write the date to the CSV file in yyyy-MM-dd format but one step at a time!

Answer

James Bassett picture James Bassett · Dec 10, 2016

While Super CSV does support reading and writing java.time.LocalDateTime via it's ParseLocalDateTime and FmtLocalDateTime cell processors (both available in the super-csv-java8 module), Dozer is trying to instantiate the destination LocalDateTime object instead of using the result of the cell processor (it's a known issue with Dozer - it doesn't support Java 8 time).

The 2 workarounds are...

Use CsvBeanReader

Swap CsvDozerBeanReader out with CsvBeanReader. You'll lose deep/indexed mapping support, but on the plus side it'll be a lot faster.

Configure Java 8 support in your DozerBeanMapper

As discussed on the Dozer issue, there is a dozer-jdk8-support library that solves this issue.

Add the dependency:

<dependency>
  <groupId>io.craftsman</groupId>
  <artifactId>dozer-jdk8-support</artifactId>
  <version>1.0.2</version>
</dependency>

Configure a DozerBeanMapper:

DozerBeanMapper beanMapper = new DozerBeanMapper();
beanMapper.setMappingFiles(Collections.singletonList("dozerJdk8Converters.xml"));

And supply it to your CsvDozerBeanReader:

new CsvDozerBeanReader(reader, CsvPreference.STANDARD_PREFERENCE, beanMapper)

It's a little bit of boilerplate, but if you really need Dozer support, this will get you up and running.

p.s. I've created a PR to have the documentation updated - only one Java 8 cell processor was listed, and there are heaps!