我如何使用杰克逊JSON映射与Java 8 LocalDateTime?
jsonmappingexception:不能实例化类型[简单类型,java.time类]的值。LocalDateTime] from JSON字符串;没有单字符串构造函数/工厂方法(通过引用链:MyDTO["field1"]->SubDTO["date"])
我如何使用杰克逊JSON映射与Java 8 LocalDateTime?
jsonmappingexception:不能实例化类型[简单类型,java.time类]的值。LocalDateTime] from JSON字符串;没有单字符串构造函数/工厂方法(通过引用链:MyDTO["field1"]->SubDTO["date"])
当前回答
对于那些正在寻找ES-8和Spring Boot:3.0版本的解决方案的人
创建一个扩展ElasticsearchConfiguration的配置文件,并覆盖clientConfiguration和elasticsearchClient的创建。
在创建elasticsearchClient期间,注入您自己的配置为使用Java 8时间模块的objectMapper,它将覆盖默认的objectMapper。
@Override
public ClientConfiguration clientConfiguration() {
return ClientConfiguration.builder()
.connectedTo(<Hostname> +":"+ <Port>)
.usingSsl()
.withBasicAuth(<Username>, <Password>)
.build();
}
@Override
public ElasticsearchClient elasticsearchClient(RestClient restClient) {
Assert.notNull(restClient, "restClient must not be null");
//Create Java8 time module
JavaTimeModule module = new JavaTimeModule();
module.addSerializer(new LocalDateTimeSerializer(DateTimeFormatter.ofPattern(DateFormat.date_time_no_millis.getPattern())));
//Register the module with objectMapper
ObjectMapper objectMapper=new ObjectMapper()
.registerModule(module);
//To convert datetime to ISO-8601
objectMapper.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS);
//Creating our own jsonpMapper
JsonpMapper jsonpMapper=new JacksonJsonpMapper(objectMapper);
// Create the transport with a Jackson mapper
ElasticsearchTransport transport = new RestClientTransport(
restClient, jsonpMapper);
// And create the API client
return new ElasticsearchClient(transport);
}
Maven的依赖:
<dependency>
<groupId>com.fasterxml.jackson.datatype</groupId>
<artifactId>jackson-datatype-jsr310</artifactId>
<version>2.14.0</version>
</dependency>
其他回答
这里不需要使用自定义序列化器/反序列化器。使用jackson-modules-java8的datetime模块:
数据类型模块,使Jackson识别Java 8日期和时间API数据类型(JSR-310)。
这个模块增加了对很多类的支持:
持续时间 即时 LocalDateTime LocalDate 本地时间 MonthDay OffsetDateTime OffsetTime 期 一年 YearMonth ZonedDateTime ZoneId ZoneOffset
如果你因为任何原因不能使用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
对于那些正在寻找ES-8和Spring Boot:3.0版本的解决方案的人
创建一个扩展ElasticsearchConfiguration的配置文件,并覆盖clientConfiguration和elasticsearchClient的创建。
在创建elasticsearchClient期间,注入您自己的配置为使用Java 8时间模块的objectMapper,它将覆盖默认的objectMapper。
@Override
public ClientConfiguration clientConfiguration() {
return ClientConfiguration.builder()
.connectedTo(<Hostname> +":"+ <Port>)
.usingSsl()
.withBasicAuth(<Username>, <Password>)
.build();
}
@Override
public ElasticsearchClient elasticsearchClient(RestClient restClient) {
Assert.notNull(restClient, "restClient must not be null");
//Create Java8 time module
JavaTimeModule module = new JavaTimeModule();
module.addSerializer(new LocalDateTimeSerializer(DateTimeFormatter.ofPattern(DateFormat.date_time_no_millis.getPattern())));
//Register the module with objectMapper
ObjectMapper objectMapper=new ObjectMapper()
.registerModule(module);
//To convert datetime to ISO-8601
objectMapper.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS);
//Creating our own jsonpMapper
JsonpMapper jsonpMapper=new JacksonJsonpMapper(objectMapper);
// Create the transport with a Jackson mapper
ElasticsearchTransport transport = new RestClientTransport(
restClient, jsonpMapper);
// And create the API client
return new ElasticsearchClient(transport);
}
Maven的依赖:
<dependency>
<groupId>com.fasterxml.jackson.datatype</groupId>
<artifactId>jackson-datatype-jsr310</artifactId>
<version>2.14.0</version>
</dependency>
我想为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);
}
}
这只是一个例子,如何使用它在一个单元测试,我黑调试这个问题。 关键成分是
mapper。registerModule(从新JavaTimeModule (); <artifactId>jack -datatyp -jsr310</artifactId>的maven dependency
代码:
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
import org.testng.Assert;
import org.testng.annotations.Test;
import java.io.IOException;
import java.io.Serializable;
import java.time.Instant;
class Mumu implements Serializable {
private Instant from;
private String text;
Mumu(Instant from, String text) {
this.from = from;
this.text = text;
}
public Mumu() {
}
public Instant getFrom() {
return from;
}
public String getText() {
return text;
}
@Override
public String toString() {
return "Mumu{" +
"from=" + from +
", text='" + text + '\'' +
'}';
}
}
public class Scratch {
@Test
public void JacksonInstant() throws IOException {
ObjectMapper mapper = new ObjectMapper();
mapper.registerModule(new JavaTimeModule());
Mumu before = new Mumu(Instant.now(), "before");
String jsonInString = mapper.writeValueAsString(before);
System.out.println("-- BEFORE --");
System.out.println(before);
System.out.println(jsonInString);
Mumu after = mapper.readValue(jsonInString, Mumu.class);
System.out.println("-- AFTER --");
System.out.println(after);
Assert.assertEquals(after.toString(), before.toString());
}
}