我们在日期字段中填充了longinlasticsearch索引。
long
字段映射为:
@Field(type = FieldType.Date) @JsonFormat(shape = JsonFormat.Shape.NUMBER_INT) private LocalDateTime created;
我使用Jackson JavaTimeModule并Jdk8Module使用以下配置:
Jackson
JavaTimeModule
Jdk8Module
@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吗?
Long
String
@JsonFormat
long->LocalDateTime
要从LocalDateTime纪元的毫秒数开始构建,1970-01-01T00:00:00Z我们需要一个时区。在2.9.9版中,当出现毫秒时,它将引发异常:
LocalDateTime
1970-01-01T00:00:00Z
不允许使用原始时间戳(1563448935000) java.time.LocalDateTime:需要其他信息,例如偏移量或时区(请参阅类Javadocs)
java.time.LocalDateTime
但是我们可以实现我们的反序列化程序,它将尝试使用默认时区进行此操作。示例实现如下所示:
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用来。您可以根据自己的意愿提供或使用系统默认值。用法示例:
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,由于这个问题,提供的代码将不会被调用,因为findAndRegisterModules在注册自定义模块后,它将被覆盖。删除该呼叫将使整个方案起作用。如果以上方法不适用于您的版本,则需要调试默认实现并查找原因。
Jackson 2.9.0
findAndRegisterModules