如何使用 Spring Boot with Jackson 在没有纳秒的情况下序列化 Instant?
How to serialize an Instant without nanoseconds using Spring Boot with Jackson?
Spring 使用 Jackson 的 InstantSerializer 像这样写出我的 Instant 字段:
now: "2021-04-07T10:51:53.043320Z"
虽然我不想要纳秒 - 只是毫秒。我猜是设置应用属性
spring.jackson.serialization.write-date-timestamps-as-nanoseconds=false
可以做到这一点,但没有区别。
如何告诉 Spring/Jackson 在序列化 Instants 时省略纳秒?
(我正在使用 Spring Boot 2.2。11.RELEASE)
更新
基于,我最终成功了。我不得不使用已弃用的 JSR310Module 而不是 JavaTimeModule,并覆盖 createContextual(...) 方法以强制它始终使用我的序列化程序。
@Bean
public ObjectMapper objectMapper(Jackson2ObjectMapperBuilder builder) {
ObjectMapper objectMapper = builder.createXmlMapper(false).build();
JSR310Module jsr310Module = new JSR310Module();
jsr310Module.addSerializer(Instant.class, new MyInstantSerializer());
objectMapper.registerModule(jsr310Module);
return objectMapper;
}
private static class MyInstantSerializer extends InstantSerializer {
public MyInstantSerializer() {
super(InstantSerializer.INSTANCE, false, false,
new DateTimeFormatterBuilder().appendInstant(3).toFormatter());
}
@Override
public JsonSerializer<?> createContextual(SerializerProvider prov, BeanProperty property) {
return this;
}
}
这也有效(基于 ):
@Bean
public Jackson2ObjectMapperBuilderCustomizer addCustomTimeSerialization() {
return jacksonObjectMapperBuilder ->
jacksonObjectMapperBuilder.serializerByType(Instant.class, new JsonSerializer<Instant>() {
private final DateTimeFormatter formatter =
new DateTimeFormatterBuilder().appendInstant(3).toFormatter();
@Override
public void serialize(
Instant instant, JsonGenerator generator, SerializerProvider provider) throws IOException {
generator.writeString(formatter.format(instant));
}
});
}
为此你可以使用 @JsonFormat(pattern = "yyyy-MM-dd'T'HH:mm:ss[.SSS]")
完整示例:
import com.fasterxml.jackson.annotation.JsonFormat;
import java.time.LocalDateTime;
import java.time.ZonedDateTime;
public class Message {
@JsonFormat(pattern = "yyyy-MM-dd'T'HH:mm:ss[.SSS]")
private final LocalDateTime dateTime;
@JsonFormat(pattern = "yyyy-MM-dd'T'HH:mm:ss[.SSS]")
private final ZonedDateTime zonedDateTime;
public Message(ZonedDateTime zonedDateTime) {
this(zonedDateTime.toLocalDateTime(), zonedDateTime);
}
public Message(LocalDateTime dateTime, ZonedDateTime zonedDateTime) {
this.dateTime = dateTime;
this.zonedDateTime = zonedDateTime;
}
public LocalDateTime getDateTime() {
return dateTime;
}
public ZonedDateTime getZonedDateTime() {
return zonedDateTime;
}
}
测试:
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.json.JsonTest;
import java.time.*;
import java.time.temporal.ChronoUnit;
import static org.junit.jupiter.api.Assertions.*;
@JsonTest
class MessageTest {
@Autowired
ObjectMapper mapper;
@Test
public void serializationTest() throws JsonProcessingException {
final LocalDate date = LocalDate.of(2000, Month.JANUARY, 1);
final LocalTime time = LocalTime.of(12, 20, 10).plus(123, ChronoUnit.MILLIS);
final Message message = new Message(ZonedDateTime.of(date, time, ZoneId.systemDefault()));
final String res = mapper.writeValueAsString(message);
assertEquals("{\"dateTime\":\"2000-01-01T12:20:10.123\",\"zonedDateTime\":\"2000-01-01T12:20:10.123\"}", res);
}
}
更新:
如果您想集中配置它,您可以:
- 尝试按照描述将日期格式设置为您的 ObjectMapper here
mapper.setDateFormat(new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS"));
- 像描述的那样自定义您的映射器
@SpringBootApplication
public class InstantSerializerApplication {
public static void main(String[] args) {
SpringApplication.run(InstantSerializerApplication.class, args);
}
@Bean
public Jackson2ObjectMapperBuilderCustomizer addCustomTimeSerialization() {
return jacksonObjectMapperBuilder -> jacksonObjectMapperBuilder.serializerByType(ZonedDateTime.class, new JsonSerializer<ZonedDateTime>() {
@Override
public void serialize(ZonedDateTime zonedDateTime, JsonGenerator jsonGenerator, SerializerProvider serializerProvider) throws IOException {
final DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss.SSS");
jsonGenerator.writeString(formatter.format(zonedDateTime));
}
});
}
}
更好的方法是
@JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd'T'HH:mm:ss.SSSZ")
private final ZonedDateTime zonedDateTime;
有关详细信息,请参阅此
的已接受答案
Spring 使用 Jackson 的 InstantSerializer 像这样写出我的 Instant 字段:
now: "2021-04-07T10:51:53.043320Z"
虽然我不想要纳秒 - 只是毫秒。我猜是设置应用属性
spring.jackson.serialization.write-date-timestamps-as-nanoseconds=false
可以做到这一点,但没有区别。
如何告诉 Spring/Jackson 在序列化 Instants 时省略纳秒?
(我正在使用 Spring Boot 2.2。11.RELEASE)
更新
基于
@Bean
public ObjectMapper objectMapper(Jackson2ObjectMapperBuilder builder) {
ObjectMapper objectMapper = builder.createXmlMapper(false).build();
JSR310Module jsr310Module = new JSR310Module();
jsr310Module.addSerializer(Instant.class, new MyInstantSerializer());
objectMapper.registerModule(jsr310Module);
return objectMapper;
}
private static class MyInstantSerializer extends InstantSerializer {
public MyInstantSerializer() {
super(InstantSerializer.INSTANCE, false, false,
new DateTimeFormatterBuilder().appendInstant(3).toFormatter());
}
@Override
public JsonSerializer<?> createContextual(SerializerProvider prov, BeanProperty property) {
return this;
}
}
这也有效(基于
@Bean
public Jackson2ObjectMapperBuilderCustomizer addCustomTimeSerialization() {
return jacksonObjectMapperBuilder ->
jacksonObjectMapperBuilder.serializerByType(Instant.class, new JsonSerializer<Instant>() {
private final DateTimeFormatter formatter =
new DateTimeFormatterBuilder().appendInstant(3).toFormatter();
@Override
public void serialize(
Instant instant, JsonGenerator generator, SerializerProvider provider) throws IOException {
generator.writeString(formatter.format(instant));
}
});
}
为此你可以使用 @JsonFormat(pattern = "yyyy-MM-dd'T'HH:mm:ss[.SSS]")
完整示例:
import com.fasterxml.jackson.annotation.JsonFormat;
import java.time.LocalDateTime;
import java.time.ZonedDateTime;
public class Message {
@JsonFormat(pattern = "yyyy-MM-dd'T'HH:mm:ss[.SSS]")
private final LocalDateTime dateTime;
@JsonFormat(pattern = "yyyy-MM-dd'T'HH:mm:ss[.SSS]")
private final ZonedDateTime zonedDateTime;
public Message(ZonedDateTime zonedDateTime) {
this(zonedDateTime.toLocalDateTime(), zonedDateTime);
}
public Message(LocalDateTime dateTime, ZonedDateTime zonedDateTime) {
this.dateTime = dateTime;
this.zonedDateTime = zonedDateTime;
}
public LocalDateTime getDateTime() {
return dateTime;
}
public ZonedDateTime getZonedDateTime() {
return zonedDateTime;
}
}
测试:
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.json.JsonTest;
import java.time.*;
import java.time.temporal.ChronoUnit;
import static org.junit.jupiter.api.Assertions.*;
@JsonTest
class MessageTest {
@Autowired
ObjectMapper mapper;
@Test
public void serializationTest() throws JsonProcessingException {
final LocalDate date = LocalDate.of(2000, Month.JANUARY, 1);
final LocalTime time = LocalTime.of(12, 20, 10).plus(123, ChronoUnit.MILLIS);
final Message message = new Message(ZonedDateTime.of(date, time, ZoneId.systemDefault()));
final String res = mapper.writeValueAsString(message);
assertEquals("{\"dateTime\":\"2000-01-01T12:20:10.123\",\"zonedDateTime\":\"2000-01-01T12:20:10.123\"}", res);
}
}
更新:
如果您想集中配置它,您可以:
- 尝试按照描述将日期格式设置为您的 ObjectMapper here
mapper.setDateFormat(new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS"));
- 像描述的那样自定义您的映射器
@SpringBootApplication
public class InstantSerializerApplication {
public static void main(String[] args) {
SpringApplication.run(InstantSerializerApplication.class, args);
}
@Bean
public Jackson2ObjectMapperBuilderCustomizer addCustomTimeSerialization() {
return jacksonObjectMapperBuilder -> jacksonObjectMapperBuilder.serializerByType(ZonedDateTime.class, new JsonSerializer<ZonedDateTime>() {
@Override
public void serialize(ZonedDateTime zonedDateTime, JsonGenerator jsonGenerator, SerializerProvider serializerProvider) throws IOException {
final DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss.SSS");
jsonGenerator.writeString(formatter.format(zonedDateTime));
}
});
}
}
更好的方法是
@JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd'T'HH:mm:ss.SSSZ")
private final ZonedDateTime zonedDateTime;
有关详细信息,请参阅此