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

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


当前回答

更新:由于历史原因,留下这个答案,但我不建议这样做。请参阅上面接受的答案。

告诉Jackson使用自定义的[反]序列化类进行映射:

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

提供自定义类:

public class LocalDateTimeSerializer extends JsonSerializer<LocalDateTime> {
    @Override
    public void serialize(LocalDateTime arg0, JsonGenerator arg1, SerializerProvider arg2) throws IOException {
        arg1.writeString(arg0.toString());
    }
}

public class LocalDateTimeDeserializer extends JsonDeserializer<LocalDateTime> {
    @Override
    public LocalDateTime deserialize(JsonParser arg0, DeserializationContext arg1) throws IOException {
        return LocalDateTime.parse(arg0.getText());
    }
}

随机事实:如果我在类上面嵌套并且不使它们静态,错误消息是奇怪的: httpmediatypenotsupportedexception:内容类型'application/json;charset=UTF-8'不支持

其他回答

对于spring引导api:

@Configuration
public class JsonConfig {

    @Bean
    public MappingJackson2HttpMessageConverter mappingJackson2HttpMessageConverter() {
        MappingJackson2HttpMessageConverter jsonConverter = new MappingJackson2HttpMessageConverter();
        ObjectMapper mapper = new ObjectMapper();

        mapper.registerModule(new ParameterNamesModule())
                .registerModule(new Jdk8Module())
                .registerModule(new JavaTimeModule());

        mapper.setSerializationInclusion(JsonInclude.Include.NON_NULL);// will remove value properties
        mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
        jsonConverter.setObjectMapper(mapper);
        return jsonConverter;
    }
}

导入以下依赖项:

implementation 'com.fasterxml.jackson.core:jackson-core:2.13.0'
implementation 'com.fasterxml.jackson.core:jackson-databind:2.13.0'
implementation 'com.fasterxml.jackson.datatype:jackson-datatype-jsr310:2.13.0'

如果您因为GraphQL Java工具而遇到此问题,并试图从日期字符串编组Java Instant,则需要设置SchemaParser以使用具有特定配置的ObjectMapper:

在GraphQLSchemaBuilder类中,注入ObjectMapper并添加以下模块:

        ObjectMapper objectMapper = 
    new ObjectMapper().registerModule(new JavaTimeModule())
            .configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false);

并将其添加到选项中:

final SchemaParserOptions options = SchemaParserOptions.newOptions()
            .objectMapperProvider(fieldDefinition -> objectMapper)
            .typeDefinitionFactory(new YourTypeDefinitionFactory())
            .build();

参见https://github.com/graphql-java-kickstart/graphql-spring-boot/issues/32

如果你因为任何原因不能使用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

如果有人在使用SpringBoot时遇到问题,这里是我在不添加新的依赖项的情况下修复问题的方法。

在Spring 2.1.3中,Jackson期望在此yyyy-MM-dd HH:mm:ss中出现日期字符串2019-05-21T07:37:11.000。在LocalDateTime中反序列化SSS格式。确保日期字符串用T分隔日期和时间,而不是用空格。秒(ss)和毫秒(SSS)可以省略。

@JsonProperty("last_charge_date")
public LocalDateTime lastChargeDate;

如果您正在使用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>>() {
            });