如何使用objectMapper设置java.time.Instant的字符串格式?
对于创建的数据字段,我有一个带有如何使用objectMapper设置java.time.Instant的字符串格式?,java,java-8,jackson,java-time,objectmapper,Java,Java 8,Jackson,Java Time,Objectmapper,对于创建的数据字段,我有一个带有java.time.Instant的实体: @Getter @Setter @AllArgsConstructor @NoArgsConstructor @EqualsAndHashCode public class Item { private String id; private String url; private Instant createdDate; } 我正在使用com.fasterxml.jackson.databind
java.time.Instant
的实体:
@Getter
@Setter
@AllArgsConstructor
@NoArgsConstructor
@EqualsAndHashCode
public class Item {
private String id;
private String url;
private Instant createdDate;
}
我正在使用com.fasterxml.jackson.databind.ObjectMapper
将项目以JSON形式保存到Elasticsearch:
bulkRequestBody.append(objectMapper.writeValueAsString(item));
ObjectMapper
将此字段序列化为对象:
"createdDate": {
"epochSecond": 1502643595,
"nano": 466000000
}
我正在尝试注释@JsonFormat(shape=JsonFormat.shape.STRING)
,但它对我不起作用
我的问题是如何将此字段序列化为
2010-05-30 22:15:52
string?您需要在下面添加依赖项
<dependency>
<groupId>com.fasterxml.jackson.datatype</groupId>
<artifactId>jackson-datatype-jsr310</artifactId>
<version>2.6.5</version>
</dependency>
一个解决方案是使用。然后,您可以向对象映射器添加JavaTimeModule
:
ObjectMapper objectMapper = new ObjectMapper();
JavaTimeModule module = new JavaTimeModule();
objectMapper.registerModule(module);
objectMapper.configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false);
默认情况下,瞬间
被序列化为历元值(单个数字中的秒和纳秒):
可以通过在对象映射器中设置来更改:
ObjectMapper objectMapper = new ObjectMapper();
JavaTimeModule module = new JavaTimeModule();
objectMapper.registerModule(module);
objectMapper.configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false);
这将产生以下输出:
{"createdDate":"2017-08-14T12:17:47.720Z"}
以上两种格式都是反序列化的,不需要任何额外的配置
要更改序列化格式,只需在字段中添加JsonFormat
注释:
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "UTC")
private Instant createdDate;
您需要设置时区,否则,即时
无法正确序列化(它会引发异常)。输出将是:
{"createdDate":"2017-08-14 12:17:47"}
{"createdDate":"2017-08-14 12:17:47"}
如果您不想(或不能)使用java8模块,另一种选择是使用
java.time.format.DateTimeFormatter
,创建自定义序列化程序和反序列化程序:
public class MyCustomSerializer extends JsonSerializer<Instant> {
private DateTimeFormatter fmt = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss").withZone(ZoneOffset.UTC);
@Override
public void serialize(Instant value, JsonGenerator gen, SerializerProvider serializers) throws IOException, JsonProcessingException {
String str = fmt.format(value);
gen.writeString(str);
}
}
public class MyCustomDeserializer extends JsonDeserializer<Instant> {
private DateTimeFormatter fmt = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss").withZone(ZoneOffset.UTC);
@Override
public Instant deserialize(JsonParser p, DeserializationContext ctxt) throws IOException, JsonProcessingException {
return Instant.from(fmt.parse(p.getText()));
}
}
输出将是:
{"createdDate":"2017-08-14 12:17:47"}
{"createdDate":"2017-08-14 12:17:47"}
一个细节是,在序列化字符串中,您将丢弃秒的分数(小数点后的所有内容)。因此,在反序列化时,无法恢复此信息(它将设置为零)
在上面的示例中,原始的
即时
是2017-08-14T12:17:47.720Z
,但序列化的字符串是2017-08-14 12:17:47
(不含秒数),因此反序列化时,结果的即时
是2017-08-14T12:17:47Z
(丢失.720
毫秒).适用于那些希望解析Java 8时间戳的人。您的POM中需要最新版本的jackson-datatype-jsr310
,并注册以下模块:
ObjectMapper objectMapper = new ObjectMapper();
objectMapper.registerModule(new JavaTimeModule());
objectMapper.configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false);
要测试此代码
@Test
void testSeliarization() throws IOException {
String expectedJson = "{\"parseDate\":\"2018-12-04T18:47:38.927Z\"}";
MyPojo pojo = new MyPojo(ZonedDateTime.parse("2018-12-04T18:47:38.927Z"));
// serialization
assertThat(objectMapper.writeValueAsString(pojo)).isEqualTo(expectedJson);
// deserialization
assertThat(objectMapper.readValue(expectedJson, MyPojo.class)).isEqualTo(pojo);
}
这里有一些Kotlin的即时格式化代码,因此它不包含毫秒,您可以使用自定义日期格式化程序
ObjectMapper().apply {
val javaTimeModule = JavaTimeModule()
javaTimeModule.addSerializer(Instant::class.java, Iso8601WithoutMillisInstantSerializer())
registerModule(javaTimeModule)
disable(WRITE_DATES_AS_TIMESTAMPS)
}
private class Iso8601WithoutMillisInstantSerializer
: InstantSerializer(InstantSerializer.INSTANCE, false, DateTimeFormatterBuilder().appendInstant(0).toFormatter())
在我的例子中,注册JavaTimeModule就足够了:
ObjectMapper objectMapper = new ObjectMapper();
JavaTimeModule module = new JavaTimeModule();
objectMapper.registerModule(module);
messageObject = objectMapper.writeValueAsString(event);
在事件对象中,我有一个类型为Instant的字段
在反序列化中,还需要注册java时间模块:
ObjectMapper objectMapper = new ObjectMapper().registerModule(new JavaTimeModule());
Event event = objectMapper.readValue(record.value(), Event.class);
您可以使用已经配置了JavaTimeModule的SpringObjectMapper。只需从Spring上下文注入它,不要使用
newObjectMapper()
如果使用Spring,并且SpringWeb
位于类路径上,则可以使用Jackson2ObjectMapperBuilder
创建ObjectMapper
。它在方法registerWellKnownModulesIfAvailable
中注册以下常用模块
com.fasterxml.jackson.datatype.jdk8.Jdk8Module
com.fasterxml.jackson.datatype.jsr310.JavaTimeModule
com.fasterxml.jackson.datatype.joda.JodaModule
com.fasterxml.jackson.module.kotlin.KotlinModule
其中一些模块已经合并到Jackson 3中;请参阅。@jbnize谢谢您的回答,我添加了
objectMapper.configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS,false)
和objectMapper.findAndRegisterModules()
它对我不起作用。您是否已将模块jar文件添加到您的类路径中?当然,确实..不适用于我的Java8模块和编译组:'com.fasterxml.jackson.module',名称:'jackson-modules-java8',版本:'2.9.0',分机:'pom'
JavaTimeModule
WRITE_DATES_AS_TIMESTAMPS
false,我得到错误no String-argument构造函数/工厂方法从字符串值('2020-08-13T10:46:16.860Z')
对于Jackson版本>2.10
,请看这一点。这里最重要的是“newObjectMapper().registerModule(newJavaTimeModule())代码>应在序列化期间处于活动状态。否则,Objectmapper将使用epochSecond
和nano
将即时数据类型转换为嵌套对象。“仅当spring web
位于类路径上时才适用。对于Jackson版本>2.10
,请参见此。