我如何使用杰克逊JSON映射与Java 8 LocalDateTime?

jsonmappingexception:不能实例化类型[简单类型,java.time类]的值。LocalDateTime] from JSON字符串;没有单字符串构造函数/工厂方法(通过引用链:MyDTO["field1"]->SubDTO["date"])


当前回答

如果你正在使用Spring引导,并且在OffsetDateTime上有这个问题,那么需要使用上面@greperror回答的registerModules(5月28日16日13:04回答),但注意有一个区别。不需要添加提到的依赖项,因为我猜spring boot已经有它了。我有这个问题与春季启动,它为我工作,没有添加这个依赖。

其他回答

您可以在应用程序中设置此参数。yml文件解析即时时间,即java8中的Date API:

spring.jackson.serialization.write-dates-as-timestamps=false

我使用这个时间格式:"{birthDate": "2018-05-24T13:56:13Z}"从json反序列化为java.time.Instant(见截图)

所有你需要知道的都在杰克逊文档里 https://www.baeldung.com/jackson-serialize-dates

9号广告很快为我解决了这个问题。

ObjectMapper mapper = new ObjectMapper();
mapper.registerModule(new JavaTimeModule());
mapper.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS);

我想为Spring的DurationStyle解析提供支持,在使用Jackson反序列化的自定义配置文件中的属性文件中提供支持,例如将20s序列化为Duration PT20S。我通过在ObjectMapper实例上注册一个自定义反序列化器来实现这一点:

@Bean("customConfigMapper")
public ObjectMapper customConfigMapper() {
    final ObjectMapper mapper = new ObjectMapper();
    final SimpleModule module = new SimpleModule();
    module.addDeserializer(Duration.class, new SpringDurationStyleDeserializer());
    mapper.registerModule(module);
    return mapper;
}

public static class SpringDurationStyleDeserializer extends JsonDeserializer<Duration> {
    @Override
    public Duration deserialize(JsonParser jsonParser, DeserializationContext __) throws IOException {
        return Optional.ofNullable(jsonParser.getText()).map(DurationStyle::detectAndParse).orElse(null);
    }
}

不幸的是,这里提出的解决方案在我的环境中不起作用。 但说实话,使用java8时间对象作为dto毕竟不是一个很好的主意。

我建议创建自定义dto,不要依赖于不稳定的库,它可能在下次jdk发布后崩溃。这种方法也符合反腐败层和适配器模式的良好实践。

下面是DTO的示例:

public class ReportDTO implements Serializable {

    private YearMonthDTO yearMonth;

    public YearMonthDTO getYearMonth() {
        return yearMonth;
    }

    public void setYearMonth(final YearMonthDTO yearMonth) {
        this.yearMonth = yearMonth;
    }

    public void fromYearMonth(final YearMonth yearMonth) {
        this.yearMonth = new YearMonthDTO(yearMonth.getYear(), 
                              yearMonth.getMonthValue());
    }

}

public static class YearMonthDTO {

    private int year;

    private int monthValue;

    public YearMonthDTO() {

    }

    public YearMonthDTO(int year, int monthValue) {
        this.year = year;
        this.monthValue = monthValue;
    }

    public int getYear() {
        return year;
    }

    public void setYear(int year) {
        this.year = year;
    }

    public int getMonthValue() {
        return monthValue;
    }

    public void setMonthValue(int monthValue) {
        this.monthValue = monthValue;
    }

}

当然,这取决于你的情况,以及你要用这个解决方案做的工作量。与任何模式一样,此解决方案并不适用于所有情况。

无论如何,目前最好的答案似乎不再适用了。我没有尝试其他解决方案,但我决定在这个简单的案例中不依赖任何库。