Jackson , java.time , ISO 8601 , 无毫秒序列化
Jackson , java.time , ISO 8601 , serialize without milliseconds
我正在使用 Jackson 2.8,需要与不允许在 ISO 8601 时间戳中使用毫秒的 API 进行通信。
预期的格式是这样的:"2016-12-24T00:00:00Z"
我正在使用 Jackson 的 JavaTimeModule,WRITE_DATES_AS_TIMESTAMPS
设置为 false
。
但这会打印毫秒数。
所以我尝试使用 objectMapper.setDateFormat
并没有改变任何东西。
我目前的解决方法是:
ObjectMapper om = new ObjectMapper();
DateTimeFormatter dtf = new DateTimeFormatterBuilder()
.appendInstant(0)
.toFormatter();
JavaTimeModule jtm = new JavaTimeModule();
jtm.addSerializer(Instant.class, new JsonSerializer<Instant>() {
@Override
public void serialize(Instant value, JsonGenerator gen, SerializerProvider serializers) throws IOException, JsonProcessingException {
gen.writeString(dtf.format(value));
}
});
om.registerModule(jtm);
我正在覆盖 Instant.class
的默认序列化程序,它可以正常工作。
有什么好的方法可以使用一些配置参数来解决这个问题吗?
更新:
只需在 Instant
属性 上方添加日期格式的 @JsonFormat
注释。非常简单。
如果您有一个带有 JavaTimeModule
的 ObjectMapper,如下所示:
ObjectMapper mapper = new ObjectMapper();
mapper.registerModule(new JavaTimeModule());
如果您有 class 和 Instant
属性,您应该添加 @JsonFormat
注释并放置没有毫秒的日期模式。接下来是这样的:
public static class TestDate {
@JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd hh:mm:ss", timezone = "UTC")
Instant instant;
//getters & setters
}
因此,如果您将对象序列化为 Json,它会完美运行:
String json = mapper.writeValueAsString(testDate);
System.out.println(json);
输出
{"instant":"2016-11-10 06:03:06"}
旧答案。我不知道为什么,但它不能正常工作:
您可以使用 Jackson2ObjectMapperBuilder
来构建它。
您只需要添加您想要的日期格式。它将类似于下一个:
DateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss");
ObjectMapper mapper = Jackson2ObjectMapperBuilder
.json()
.featuresToDisable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS)
.modules(new JavaTimeModule())
.dateFormat(dateFormat)
.build();
这是您可以全局设置的替代方案,但需要您将 ZonedDateTime
与即时格式化程序一起使用,因为我们无法设置 Instant
序列化程序的格式 Java 时间模块.
您不会看到使用即时分区日期时间的任何副作用,因为杰克逊单独序列化区域 ID 并且默认情况下处于禁用状态。所以从技术上讲,这类似于将格式化程序应用于 Instant
。
以这种方式使用时,ZonedDateTime
序列化程序将序列化委托给 InstantBaseSerializer
并使用指定的自定义格式。
@RunWith(JUnit4.class)
public class InstantNoMillisTest {
private ObjectMapper objectMapper;
@Before
public void init() {
JavaTimeModule module = new JavaTimeModule();
ZonedDateTimeSerializer zonedDateTimeSerializer = new ZonedDateTimeSerializer(new DateTimeFormatterBuilder().appendInstant(0).toFormatter());
module.addSerializer(ZonedDateTime.class, zonedDateTimeSerializer);
module.addDeserializer(ZonedDateTime.class, InstantDeserializer.ZONED_DATE_TIME);
objectMapper = Jackson2ObjectMapperBuilder.json()
.modules(module)
.featuresToDisable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS)
.build();
}
@Test
public void serialize() throws IOException {
ZonedDateTime zonedDateTime = ZonedDateTime.now();
String noMillis = objectMapper.writeValueAsString(zonedDateTime);
System.out.print(noMillis);
}
@Test
public void deserialize() throws IOException {
String dateTime = "\"2017-10-26T12:54:59Z\"";
ZonedDateTime noMillis = objectMapper.readValue(dateTime, ZonedDateTime.class);
System.out.print(noMillis);
}
}
这里有一些格式化 Instant
字段的 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())
我正在使用 Jackson 2.8,需要与不允许在 ISO 8601 时间戳中使用毫秒的 API 进行通信。
预期的格式是这样的:"2016-12-24T00:00:00Z"
我正在使用 Jackson 的 JavaTimeModule,WRITE_DATES_AS_TIMESTAMPS
设置为 false
。
但这会打印毫秒数。
所以我尝试使用 objectMapper.setDateFormat
并没有改变任何东西。
我目前的解决方法是:
ObjectMapper om = new ObjectMapper();
DateTimeFormatter dtf = new DateTimeFormatterBuilder()
.appendInstant(0)
.toFormatter();
JavaTimeModule jtm = new JavaTimeModule();
jtm.addSerializer(Instant.class, new JsonSerializer<Instant>() {
@Override
public void serialize(Instant value, JsonGenerator gen, SerializerProvider serializers) throws IOException, JsonProcessingException {
gen.writeString(dtf.format(value));
}
});
om.registerModule(jtm);
我正在覆盖 Instant.class
的默认序列化程序,它可以正常工作。
有什么好的方法可以使用一些配置参数来解决这个问题吗?
更新:
只需在 Instant
属性 上方添加日期格式的 @JsonFormat
注释。非常简单。
如果您有一个带有 JavaTimeModule
的 ObjectMapper,如下所示:
ObjectMapper mapper = new ObjectMapper();
mapper.registerModule(new JavaTimeModule());
如果您有 class 和 Instant
属性,您应该添加 @JsonFormat
注释并放置没有毫秒的日期模式。接下来是这样的:
public static class TestDate {
@JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd hh:mm:ss", timezone = "UTC")
Instant instant;
//getters & setters
}
因此,如果您将对象序列化为 Json,它会完美运行:
String json = mapper.writeValueAsString(testDate);
System.out.println(json);
输出
{"instant":"2016-11-10 06:03:06"}
旧答案。我不知道为什么,但它不能正常工作:
您可以使用 Jackson2ObjectMapperBuilder
来构建它。
您只需要添加您想要的日期格式。它将类似于下一个:
DateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss");
ObjectMapper mapper = Jackson2ObjectMapperBuilder
.json()
.featuresToDisable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS)
.modules(new JavaTimeModule())
.dateFormat(dateFormat)
.build();
这是您可以全局设置的替代方案,但需要您将 ZonedDateTime
与即时格式化程序一起使用,因为我们无法设置 Instant
序列化程序的格式 Java 时间模块.
您不会看到使用即时分区日期时间的任何副作用,因为杰克逊单独序列化区域 ID 并且默认情况下处于禁用状态。所以从技术上讲,这类似于将格式化程序应用于 Instant
。
以这种方式使用时,ZonedDateTime
序列化程序将序列化委托给 InstantBaseSerializer
并使用指定的自定义格式。
@RunWith(JUnit4.class)
public class InstantNoMillisTest {
private ObjectMapper objectMapper;
@Before
public void init() {
JavaTimeModule module = new JavaTimeModule();
ZonedDateTimeSerializer zonedDateTimeSerializer = new ZonedDateTimeSerializer(new DateTimeFormatterBuilder().appendInstant(0).toFormatter());
module.addSerializer(ZonedDateTime.class, zonedDateTimeSerializer);
module.addDeserializer(ZonedDateTime.class, InstantDeserializer.ZONED_DATE_TIME);
objectMapper = Jackson2ObjectMapperBuilder.json()
.modules(module)
.featuresToDisable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS)
.build();
}
@Test
public void serialize() throws IOException {
ZonedDateTime zonedDateTime = ZonedDateTime.now();
String noMillis = objectMapper.writeValueAsString(zonedDateTime);
System.out.print(noMillis);
}
@Test
public void deserialize() throws IOException {
String dateTime = "\"2017-10-26T12:54:59Z\"";
ZonedDateTime noMillis = objectMapper.readValue(dateTime, ZonedDateTime.class);
System.out.print(noMillis);
}
}
这里有一些格式化 Instant
字段的 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())