使用Jackson从字符串反序列化LocalDateTime

10

我正尝试使用Jackson将一个String反序列化为LocalDateTime,但它无法工作。

我有一个包含LocalDateTime字段的数据类:

@Data
public class Registration {
    @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd hh:mm:ss")
    private LocalDateTime timestamp;
}

我添加了特殊的Jackson数据类型模块:

compile("com.fasterxml.jackson.datatype:jackson-datatype-jsr310")

序列化在以下情况下工作正常:

new ObjectMapper().registerModule(new JavaTimeModule()).writeValueAsString(registration);

结果字符串:

{"timestamp":"2018-09-03 10:09:35"}

但是反序列化不能使用:

new ObjectMapper().registerModule(new JavaTimeModule()).readValue(json.traverse(), Registration.class)

我得到的错误信息是:

Cannot deserialize value of type `java.time.LocalDateTime` from String "2018-09-03 10:09:35": 
    Failed to deserialize java.time.LocalDateTime: 
        (java.time.format.DateTimeParseException) Text '2018-09-03 10:09:35' could not be parsed: 
            Unable to obtain LocalDateTime from TemporalAccessor: 
                {MinuteOfHour=9, NanoOfSecond=0, SecondOfMinute=35, MicroOfSecond=0, MilliOfSecond=0, HourOfAmPm=10},
                ISO resolved to 2018-09-03 of type java.time.format.Parsed

我错过了什么?我感到困惑的是序列化可以正常工作,但反序列化却不能。


MWE:(一个小的Gradle Java项目)

Main.java:

import java.io.IOException;
import java.time.LocalDateTime;

import com.fasterxml.jackson.annotation.JsonFormat;
import com.fasterxml.jackson.core.TreeNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;

public class Main {

    public static void main(String[] args) throws IOException {
        Registration registration = new Registration();
        registration.setTimestamp(LocalDateTime.now());

         ObjectMapper objectMapper = new ObjectMapper().registerModule(new JavaTimeModule());

         String s = objectMapper.writeValueAsString(registration);
         TreeNode treeNode = objectMapper.readTree(s);

         //Fails here:
         Registration registration1 = objectMapper.readValue(treeNode.traverse(), Registration.class);

        System.out.println(registration1);
    }
}

class Registration {
    @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd hh:mm:ss")
    private LocalDateTime timestamp;

    public Registration() {
    }

    public LocalDateTime getTimestamp() {
        return this.timestamp;
    }

    public void setTimestamp(LocalDateTime localDateTime) {
        this.timestamp = localDateTime;
    }
}

build.gradle:

plugins {
    id 'java'
}

group 'dateMWE'
version '1.0-SNAPSHOT'

sourceCompatibility = 10

repositories {
    mavenCentral()
}

dependencies {
    compile("com.fasterxml.jackson.core:jackson-annotations:2.9.6")
    compile("com.fasterxml.jackson.datatype:jackson-datatype-jsr310:2.9.6")
}
2个回答

19
问题与JSON反序列化无关,而是与时间格式字符串相关:
pattern = "yyyy-MM-dd hh:mm:ss"
请注意,小时设置为hh:这是一个12小时制的格式化程序,需要"AM"或"PM"值。
如果将模式更改为:
pattern = "yyyy-MM-dd HH:mm:ss"

问题应该解决。


没错。我尝试了一下这个模式,但是我找不到任何关于存在哪些模式/关键字的详细文档。你能否添加一个链接,列出所有可能的格式选项的文档或列表? - Spenhouet
1
@Spen:DataTimeFormatter模式在标准的Java API文档中有详细记录。 - Antot
感谢您挽救了我的一天。我参考了https://dev59.com/A7Dla4cB1Zd3GeqP94-Q#54819859这个答案,但是代码没有起作用。错误日志不是很直观。 - Da Tong

14

由于您使用new创建对象,因此您的ObjectMapper未由Spring管理。在配置文件中将ObjectMapper配置为Bean。您需要使用LocalDateTimeDeserializer注册DateTimeFormat,并在JavaTimeModule中设置您的Deserializer。

@Bean
public ObjectMapper objectMapper() {
    JavaTimeModule module = new JavaTimeModule();
    LocalDateTimeDeserializer localDateTimeDeserializer = new
            LocalDateTimeDeserializer(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss"));
    module.addDeserializer(LocalDateTime.class, localDateTimeDeserializer);
    ObjectMapper objectMapperObj = Jackson2ObjectMapperBuilder.json()
            .modules(module)
            .featuresToDisable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS)
            .build();
    return objectMapperObj;
}

将上述配置设置在您的Spring配置文件中。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接