NoSuchMethodException: java.time.LocalDateTime.<init>() 使用 Super CSV 读取 CSV
NoSuchMethodException: java.time.LocalDateTime.<init>() reading CSV using Super CSV
我使用 Super CSV's ICsvDozerBeanWriter
将仅包含 LocalDateTime
的实体写入 CSV 文件,但在使用 [=15= 读回时遇到错误].我能够成功读取和写入 Date
对象,但 LocalDateTime
不工作。
我添加了 super-csv-java8 依赖项,编写部分似乎工作正常。
我创建了一个小型演示应用程序 in this Github repo 来重现该问题。 运行 main() 方法和错误将输出到控制台。
这是我遇到的异常:
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)
理想情况下,我想以 yyyy-MM-dd 格式将日期写入 CSV 文件,但一次一步!
LocalDateTime 是一个不可变对象并且:
如果没有偏移量或时区等附加信息,它不能表示时间线上的瞬间。
来源:https://docs.oracle.com/javase/8/docs/api/java/time/LocalDateTime.html
所以你正在尝试为一开始就无法实例化的东西重建一个实例。
可能的解决方案:为什么不保存所需日期的字符串表示形式,然后将其解析回 LocalDateTime?
LocalDateTime
不是片刻
是正确的。 LocalDateTime
是错误的 class 用于某个时间点。由于没有时区或与 UTC 的偏移量的概念,class 只是对可能时刻的模糊概念。 在您应用时区或偏移量之前没有实际意义。
自定义细胞处理器
我不是 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 方面的专家。
查看 this list of built-in cell processors,似乎库确实尚未针对 java.time 类型进行更新。
我在 your example app 中看不到任何映射或自定义单元处理器。
Instant
要表示一个时刻,时间轴上的一个点,请使用 Instant
class。
Instant
class represents a moment on the timeline in UTC with a resolution of nanoseconds(最多九 (9) 位小数)。
Instant instant = Instant.now(); // Current moment in UTC.
ISO 8601
ISO 8601 标准为序列化为文本的日期时间值定义了许多格式。这些对于跨文化的人来说是实用的、明确的、易于解析的和直观的。
java.time classes 在 parsing/generating 字符串时默认使用这些格式。这包括 Instant
class.
String output = instant.toString();
2016-12-09T22:27:17.783Z
Instant instant = Instant.parse( "2016-12-09T22:27:17.783Z" );
除了 Instant
之外,您还可以从 OffsetDateTime
class 和 ZonedDateTime
class 生成字符串。它们也可以使用 ISO 8601 生成用于双向数据交换的双字符串。在 ZonedDateTime
的情况下, toString
方法通过明智地在方括号中附加时区名称来扩展 ISO 8601 格式.但通常最好使用 UTC (Instant
) 值。
虽然 Super CSV 确实 支持读取和写入 java.time.LocalDateTime
通过它的 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 - 它不支持 Java 8 时间).
两个解决方法是...
使用 CsvBeanReader
将 CsvDozerBeanReader
换成 CsvBeanReader
。您将失去 deep/indexed 映射支持,但从好的方面来说它会快得多。
在您的 DozerBeanMapper
中配置 Java 8 支持
正如在 Dozer 问题上所讨论的,有一个 dozer-jdk8-support 库可以解决这个问题。
添加依赖:
<dependency>
<groupId>io.craftsman</groupId>
<artifactId>dozer-jdk8-support</artifactId>
<version>1.0.2</version>
</dependency>
配置一个DozerBeanMapper
:
DozerBeanMapper beanMapper = new DozerBeanMapper();
beanMapper.setMappingFiles(Collections.singletonList("dozerJdk8Converters.xml"));
并将其提供给您的 CsvDozerBeanReader
:
new CsvDozerBeanReader(reader, CsvPreference.STANDARD_PREFERENCE, beanMapper)
这有点样板,但如果你真的需要推土机支持,这会让你起来 运行。
p.s。我创建了一个 PR to have the documentation 更新 - 只列出了一个 Java 8 单元处理器,还有堆!
我使用 Super CSV's ICsvDozerBeanWriter
将仅包含 LocalDateTime
的实体写入 CSV 文件,但在使用 [=15= 读回时遇到错误].我能够成功读取和写入 Date
对象,但 LocalDateTime
不工作。
我添加了 super-csv-java8 依赖项,编写部分似乎工作正常。
我创建了一个小型演示应用程序 in this Github repo 来重现该问题。 运行 main() 方法和错误将输出到控制台。
这是我遇到的异常:
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)
理想情况下,我想以 yyyy-MM-dd 格式将日期写入 CSV 文件,但一次一步!
LocalDateTime 是一个不可变对象并且: 如果没有偏移量或时区等附加信息,它不能表示时间线上的瞬间。
来源:https://docs.oracle.com/javase/8/docs/api/java/time/LocalDateTime.html
所以你正在尝试为一开始就无法实例化的东西重建一个实例。
可能的解决方案:为什么不保存所需日期的字符串表示形式,然后将其解析回 LocalDateTime?
LocalDateTime
不是片刻
LocalDateTime
是错误的 class 用于某个时间点。由于没有时区或与 UTC 的偏移量的概念,class 只是对可能时刻的模糊概念。 在您应用时区或偏移量之前没有实际意义。
自定义细胞处理器
我不是 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 方面的专家。
查看 this list of built-in cell processors,似乎库确实尚未针对 java.time 类型进行更新。
我在 your example app 中看不到任何映射或自定义单元处理器。
Instant
要表示一个时刻,时间轴上的一个点,请使用 Instant
class。
Instant
class represents a moment on the timeline in UTC with a resolution of nanoseconds(最多九 (9) 位小数)。
Instant instant = Instant.now(); // Current moment in UTC.
ISO 8601
ISO 8601 标准为序列化为文本的日期时间值定义了许多格式。这些对于跨文化的人来说是实用的、明确的、易于解析的和直观的。
java.time classes 在 parsing/generating 字符串时默认使用这些格式。这包括 Instant
class.
String output = instant.toString();
2016-12-09T22:27:17.783Z
Instant instant = Instant.parse( "2016-12-09T22:27:17.783Z" );
除了 Instant
之外,您还可以从 OffsetDateTime
class 和 ZonedDateTime
class 生成字符串。它们也可以使用 ISO 8601 生成用于双向数据交换的双字符串。在 ZonedDateTime
的情况下, toString
方法通过明智地在方括号中附加时区名称来扩展 ISO 8601 格式.但通常最好使用 UTC (Instant
) 值。
虽然 Super CSV 确实 支持读取和写入 java.time.LocalDateTime
通过它的 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 - 它不支持 Java 8 时间).
两个解决方法是...
使用 CsvBeanReader
将 CsvDozerBeanReader
换成 CsvBeanReader
。您将失去 deep/indexed 映射支持,但从好的方面来说它会快得多。
在您的 DozerBeanMapper
中配置 Java 8 支持正如在 Dozer 问题上所讨论的,有一个 dozer-jdk8-support 库可以解决这个问题。
添加依赖:
<dependency>
<groupId>io.craftsman</groupId>
<artifactId>dozer-jdk8-support</artifactId>
<version>1.0.2</version>
</dependency>
配置一个DozerBeanMapper
:
DozerBeanMapper beanMapper = new DozerBeanMapper();
beanMapper.setMappingFiles(Collections.singletonList("dozerJdk8Converters.xml"));
并将其提供给您的 CsvDozerBeanReader
:
new CsvDozerBeanReader(reader, CsvPreference.STANDARD_PREFERENCE, beanMapper)
这有点样板,但如果你真的需要推土机支持,这会让你起来 运行。
p.s。我创建了一个 PR to have the documentation 更新 - 只列出了一个 Java 8 单元处理器,还有堆!