NoSuchMethodException: java.time.LocalDateTime.<init>() reading CSV using Super CSV
Solution 1
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!
Solution 2
LocalDateTime is an immutable object and: It cannot represent an instant on the time-line without additional information such as an offset or time-zone.
source: https://docs.oracle.com/javase/8/docs/api/java/time/LocalDateTime.html
So you are trying to reconstruct an instance for something that cannot be instantiated in the first place.
possible solution: Why don't you save a string representation of the date you need and then parse it back to a LocalDateTime ?
Solution 3
LocalDateTime
is not a moment
The Answer by moldovean is correct. LocalDateTime
is the wrong class to use for a point in time. Having no concept of time zone or offset-from-UTC, this class is only a vague idea of possible moments. Has no real meaning until you apply a time zone or offset.
Custom cell processor
I'm no expert on SuperCSV. I cannot find full documentation discussing what data types it handles automatically. If this library has not yet been updated to handle the java.time types directly, you will need to write your own mapping implementation, apparently a custom cell processor.
Looking at this list of built-in cell processors, it seems that indeed the library has not yet been updated for java.time types.
I see no mapping or custom cell processor in your example app.
Instant
To represent a moment, a point on the timeline, use the Instant
class.
The Instant
class represents a moment on the timeline in UTC with a resolution of nanoseconds (up to nine (9) digits of a decimal fraction).
Instant instant = Instant.now(); // Current moment in UTC.
ISO 8601
The ISO 8601 standard defines many formats for date-time values being serialized as text. These are practical, unambiguous, easy to parse, and intuitive for humans across cultures.
The java.time classes use these formats by default when parsing/generating strings. This includes the Instant
class.
String output = instant.toString();
2016-12-09T22:27:17.783Z
Instant instant = Instant.parse( "2016-12-09T22:27:17.783Z" );
You can also generate strings from the OffsetDateTime
class and ZonedDateTime
class in addition to Instant
. They too can generate bi-strings for bi-directional data exchange using ISO 8601. In the case of ZonedDateTime
the toString
method extends the ISO 8601 format by wisely appending the name of the time zone in square brackets. But generally best to work with UTC (Instant
) values.
Stuart Leyland-Cole
Updated on June 11, 2022Comments
-
Stuart Leyland-Cole about 2 years
I have written an entity that contains just a
LocalDateTime
to a CSV file using Super CSV'sICsvDozerBeanWriter
and I am encountering an error when reading it back using aICsvDozerBeanReader
. I was able to successfully read and write aDate
object butLocalDateTime
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!
-
calvin.mk over 5 yearsI have added the dozer-jdk8-support to my project and added dozerJdk8Converters.xml under
src/main/resources
in my maven based project, as directed here. But am still getting same error that of org.dozer.MappingException: java.lang.NoSuchMethodException: java.time.LocalDateTime.<init>(). Any idea what's going wrong ?