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

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


当前回答

@JsonDeserialize(using = LocalDateTimeDeserializer.class)
@JsonSerialize(using = LocalDateTimeSerializer.class)
private LocalDateTime createTime;

这对我来说很有效。

其他回答

如果你正在使用Jackson Serializer,下面是一种使用date模块的方法:

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.datatype.jdk8.Jdk8Module;
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
import com.fasterxml.jackson.module.paramnames.ParameterNamesModule;
import org.apache.kafka.common.serialization.Serializer;

public class JacksonSerializer<T> implements Serializer<T> {

    private final ObjectMapper mapper = new ObjectMapper()
            .registerModule(new ParameterNamesModule())
            .registerModule(new Jdk8Module())
            .registerModule(new JavaTimeModule());

    @Override
    public byte[] serialize(String s, T object) {
        try {
            return mapper.writeValueAsBytes(object);
        } catch (JsonProcessingException e) {
            e.printStackTrace();
        }
        return null;
    }
}

如果您正在使用fastxml的ObjectMapper类, 默认情况下,ObjectMapper不理解LocalDateTime类,所以,你需要在你的gradle/maven中添加另一个依赖项:

compile 'com.fasterxml.jackson.datatype:jackson-datatype-jsr310:2.7.3'

现在你需要将这个库提供的数据类型支持注册到你的objectmapper对象中,这可以通过以下方式完成:

ObjectMapper objectMapper = new ObjectMapper();
objectMapper.findAndRegisterModules();

现在,在你的jsonString中,你可以很容易地把你的java。LocalDateTime字段如下所示:

{
    "user_id": 1,
    "score": 9,
    "date_time": "2016-05-28T17:39:44.937"
}

通过这样做,你的Json文件到Java对象的转换将工作良好,你可以通过以下方式读取文件:

objectMapper.readValue(jsonString, new TypeReference<List<User>>() {
            });

我想为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);
    }
}

如果你因为任何原因不能使用jackson-modules-java8,你可以(反)序列化即时字段,只要使用@JsonIgnore和@JsonGetter和@JsonSetter:

public class MyBean {

    private Instant time = Instant.now();

    @JsonIgnore
    public Instant getTime() {
        return this.time;
    }

    public void setTime(Instant time) {
        this.time = time;
    }

    @JsonGetter
    private long getEpochTime() {
        return this.time.toEpochMilli();
    }

    @JsonSetter
    private void setEpochTime(long time) {
        this.time = Instant.ofEpochMilli(time);
    }
}

例子:

@Test
public void testJsonTime() throws Exception {
    String json = new ObjectMapper().writeValueAsString(new MyBean());
    System.out.println(json);
    MyBean myBean = new ObjectMapper().readValue(json, MyBean.class);
    System.out.println(myBean.getTime());
}

收益率

{"epochTime":1506432517242}
2017-09-26T13:28:37.242Z

对于使用Spring Boot 2.x的用户

上面这些都不需要做——Java 8 LocalDateTime是开箱即用的序列化/反序列化。我必须在1年内完成以上所有工作。x,但是使用Boot 2。X,它可以无缝工作。

在Spring Boot中也可以看到JSON Java 8 LocalDateTime格式