Force Milliseconds When Serializing Instant to ISO8601 using Jackson

前端 未结 5 599
野的像风
野的像风 2021-01-11 15:01

I have some questions related to JSON serialization using Jackson in a project where I use Spring Boot 2.0.0.M6, Spring Framework 5.0.1.R

相关标签:
5条回答
  • 2021-01-11 15:16

    I solve using this aproach:

    ObjectMapper objectMapper = new ObjectMapper();
    JavaTimeModule module = new JavaTimeModule();
    module.addSerializer(Instant.class, new InstantSerializerWithMilliSecondPrecision());
    objectMapper.registerModule(module);
    

    And for InstantSerializerWithMilliSecondPrecision i used this:

    public class InstantSerializerWithMilliSecondPrecision extends InstantSerializer {
    
        public InstantSerializerWithMilliSecondPrecision() {
            super(InstantSerializer.INSTANCE, false, new DateTimeFormatterBuilder().appendInstant(3).toFormatter());
        }
    }
    

    Now the Instant serialization always includes milliseconds. Example: 2019-09-27T02:59:59.000Z

    0 讨论(0)
  • 2021-01-11 15:21

    Solve it by using custom serializers for LocalDateTime and ZonedDateTime classes.

    My solution works for me because I use only these two classes in API responses to represent date and time! I don't use Instant or Date so pay attention on it.

    @Configuration
    class JacksonConfig {
    
    @Bean
    fun objectMapper(): ObjectMapper {
        val mapper = ObjectMapper()
        val javaTimeModule = JavaTimeModule().apply {
            addSerializer(LocalDateTime::class.java, KeepMillisecondLocalDateTimeSerializer())
            addSerializer(ZonedDateTime::class.java, KeepMillisecondZonedDateTimeSerializer())
        }
        mapper.registerModule(javaTimeModule)
        return mapper
    }
    
    class KeepMillisecondZonedDateTimeSerializer : JsonSerializer<ZonedDateTime>() {
        private val formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss.SSSX")
    
        @Throws(IOException::class)
        override fun serialize(
            value: ZonedDateTime,
            jsonGenerator: JsonGenerator,
            serializerProvider: SerializerProvider?
        ) {
            jsonGenerator.writeString(formatter.format(value))
        }
    }
    
    class KeepMillisecondLocalDateTimeSerializer : JsonSerializer<LocalDateTime>() {
        private val formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss.SSS")
    
        @Throws(IOException::class)
        override fun serialize(
            value: LocalDateTime,
            jsonGenerator: JsonGenerator,
            serializerProvider: SerializerProvider?
        ) {
            jsonGenerator.writeString(formatter.format(value))
        }
    }
    }
    
    0 讨论(0)
  • 2021-01-11 15:24

    There appears to be a Jackson issue open for this here*. That link contains two workarounds

    Workaround 1

     ObjectMapper objectMapper = new ObjectMapper();
        objectMapper.registerModule(new JavaTimeModule());
        SimpleModule module = new SimpleModule();
        module.addSerializer(ZonedDateTime.class, new JsonSerializer<ZonedDateTime>() {
            @Override
            public void serialize(ZonedDateTime zonedDateTime, JsonGenerator jsonGenerator, SerializerProvider serializerProvider) throws IOException, JsonProcessingException {
                jsonGenerator.writeString(DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss.SSSZZZ").format(zonedDateTime));
            }
        });
        objectMapper.registerModule(module);
        objectMapper.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS);
        objectMapper.enable(SerializationFeature.INDENT_OUTPUT);
    

    Workaround 2

    JavaTimeModule javaTimeModule = new JavaTimeModule();
    javaTimeModule.addSerializer(ZonedDateTime.class,
      new ZonedDateTimeSerializer(DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss.SSSX")));
    ObjectMapper mapper = new ObjectMapper().registerModule(javaTimeModule);
    

    *Link is dead because they deprecated FasterXML/jackson-datatype-jsr310 and moved it to jackson-modules-java8. See https://github.com/FasterXML/jackson-modules-java8/issues/76

    0 讨论(0)
  • 2021-01-11 15:38

    None of two workarounds mentioned by Sean Carroll works me. I end up with writing my own serializer for Instant.

    final ObjectMapper mapper = new ObjectMapper();
    final JavaTimeModule javaTimeModule = new JavaTimeModule();
    javaTimeModule.addSerializer(Instant.class, new KeepMillisecondInstantSerializer());
    mapper.registerModule(javaTimeModule);
    
    public class KeepMillisecondInstantSerializer extends JsonSerializer<Instant> {
    
        private final DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss.SSSX")
                .withZone(ZoneId.of("UTC"));
    
        @Override
        public void serialize(final Instant instant, final JsonGenerator jsonGenerator, final SerializerProvider serializerProvider) throws IOException {
            final String serializedInstant = dateTimeFormatter.format(instant);
            jsonGenerator.writeString(serializedInstant);
        }
    }
    

    I guess Jackson use Instant.toString() method to serialize Instant objects by default. I also find some discussions about Instant.toString() method on StackOverflow.

    0 讨论(0)
  • 2021-01-11 15:40

    Rather than fixing the bug of Jackson library, following could be a quick work around: Create a string variable in the POJO class where you have Timestamp variable:

    private Timestamp createTimeStamp;
    
    private String stringCreateTimeStamp;   
    

    capture timestamp value as a string:

    listOfPojo.forEach(pojo-> {
                pojo.setStringCreateTimeStamp(request.getcreateTimeStamp().toString());
            });
    

    Refer https://www.baeldung.com/java-string-to-timestamp for conversions

    0 讨论(0)
提交回复
热议问题