gpt4 book ai didi

java - Jackson 使用 Java 8 将 elasticsearch 反序列化为 LocalDateTime

转载 作者:行者123 更新时间:2023-11-29 04:08:00 24 4
gpt4 key购买 nike

我们在 elasticsearch 索引中有一个用 long 填充的日期字段。

字段映射为:

@Field(type = FieldType.Date)
@JsonFormat(shape = JsonFormat.Shape.NUMBER_INT)
private LocalDateTime created;

我使用 Jackson JavaTimeModuleJdk8Module 配置:

@Bean
public ElasticsearchOperations elasticsearchTemplate() {
return new ElasticsearchRestTemplate(client(), new CustomEntityMapper());
}

public static class CustomEntityMapper implements EntityMapper {

private final ObjectMapper objectMapper;

public CustomEntityMapper() {
//we use this so that Elasticsearch understands LocalDate and LocalDateTime objects
objectMapper = new ObjectMapper()
.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false)
.configure(DeserializationFeature.ACCEPT_SINGLE_VALUE_AS_ARRAY, true)
.configure(DeserializationFeature.READ_DATE_TIMESTAMPS_AS_NANOSECONDS, false)
.configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false)
.configure(SerializationFeature.WRITE_DATE_TIMESTAMPS_AS_NANOSECONDS, false)
//MUST be registered BEFORE calling findAndRegisterModules
.registerModule(new JavaTimeModule())
.registerModule(new Jdk8Module());
//only autodetect fields and ignore getters and setters for nonexistent fields when serializing/deserializing
objectMapper.setVisibility(objectMapper.getSerializationConfig().getDefaultVisibilityChecker()
.withFieldVisibility(JsonAutoDetect.Visibility.ANY)
.withGetterVisibility(JsonAutoDetect.Visibility.NONE)
.withSetterVisibility(JsonAutoDetect.Visibility.NONE)
.withCreatorVisibility(JsonAutoDetect.Visibility.NONE));
//load the other available modules as well
objectMapper.findAndRegisterModules();
}

@Override
public String mapToString(Object object) throws IOException {
return objectMapper.writeValueAsString(object);
}

@Override
public <T> T mapToObject(String source, Class<T> clazz) throws IOException {
return objectMapper.readValue(source, clazz);
}
}

但是当我尝试使用以下字段解析索引中的实体时:

"created" : 1563448935000

我得到一个错误:

com.fasterxml.jackson.databind.exc.MismatchedInputException: Unexpected token (VALUE_NUMBER_INT), expected VALUE_STRING: Expected array or string.

我认为,可以将一个 long 反序列化为一个日期,但我没有看到我遗漏了什么。

如果我将它映射到 Long 它当然可以工作,如果值存储为 String 并且我们在 @JsonFormat。但是也可以有 long->LocalDateTime 吗?

最佳答案

要从 1970-01-01T00:00:00Z 的纪元开始以毫秒为单位构建 LocalDateTime,我们需要一个时区。在版本 2.9.9出现毫秒时抛出异常:

raw timestamp (1563448935000) not allowed for java.time.LocalDateTime: need additional information such as an offset or time-zone (see class Javadocs)

但是我们可以实现我们的反序列化器,它将尝试使用默认时区执行此操作。示例实现如下所示:

class MillisOrLocalDateTimeDeserializer extends LocalDateTimeDeserializer {

public MillisOrLocalDateTimeDeserializer() {
super(DateTimeFormatter.ISO_LOCAL_DATE_TIME);
}

@Override
public LocalDateTime deserialize(JsonParser parser, DeserializationContext context) throws IOException {
if (parser.hasToken(JsonToken.VALUE_NUMBER_INT)) {
long value = parser.getValueAsLong();
Instant instant = Instant.ofEpochMilli(value);

return LocalDateTime.ofInstant(instant, ZoneOffset.UTC);
}

return super.deserialize(parser, context);
}

}
使用

ZoneOffset.UTC。在您的情况下,您可以提供您的或使用系统默认值。用法示例:

import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.core.JsonToken;
import com.fasterxml.jackson.databind.DeserializationContext;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
import com.fasterxml.jackson.datatype.jsr310.deser.LocalDateTimeDeserializer;

import java.io.IOException;
import java.time.Instant;
import java.time.LocalDateTime;
import java.time.ZoneOffset;
import java.time.format.DateTimeFormatter;

public class JsonApp {

public static void main(String[] args) throws Exception {
JavaTimeModule javaTimeModule = new JavaTimeModule();
// override default
javaTimeModule.addDeserializer(LocalDateTime.class, new MillisOrLocalDateTimeDeserializer());

ObjectMapper mapper = new ObjectMapper();
mapper.registerModule(javaTimeModule);

String json = "{\"created\":1563448935000}";
System.out.println(mapper.readValue(json, Created.class));

}
}

class Created {

private LocalDateTime created;

// getters, setters, toString
}

以上代码打印:

Created{created=2019-07-18T11:22:15}

编辑:使用 Jackson 2.9.0,因为 this问题提供的代码将不会被调用,因为在注册自定义模块后调用的 findAndRegisterModules 将覆盖它。删除该调用将使整个场景正常工作。如果以上不适用于您的版本,您需要调试默认实现并找出原因。

关于java - Jackson 使用 Java 8 将 elasticsearch 反序列化为 LocalDateTime,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57098784/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com