使用Jackson

时间:2017-11-26 23:32:25

标签: java json spring spring-boot jackson2

在我使用Spring Boot 2.0.0.M6Spring Framework 5.0.1.RELEASEJackson 2.9.2的项目中,我有一些与使用杰克逊的 JSON序列化相关的问题。

我在application.properties中配置了以下与杰克逊相关的设置:

spring.jackson.serialization.WRITE_DATES_AS_TIMESTAMPS=false

序列化主要按照我的需要工作。尽管如此,我注意到杰克逊似乎截止了毫秒,如果它们是000

测试1:序列化Instant,毫秒设置为000

  • 使用Instant.parse("2017-09-14T04:28:48.000Z")
  • 初始化即时字段
  • 使用杰克逊
  • 序列化
  • 输出将为"2017-09-14T04:28:48Z"

测试2:序列化Instant,毫秒设置为某个非000值:

  • 使用Instant.parse("2017-09-14T04:28:48.100Z")
  • 初始化即时字段
  • 使用杰克逊
  • 序列化
  • 输出将为"2017-09-14T04:28:48.100Z"

问题

  • 这是设计的行为吗?
  • 我有什么办法可以强制000
  • 的序列化

5 个答案:

答案 0 :(得分:3)

似乎有一个杰克逊问题对此here *开放。该链接包含两个解决方法

解决方法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);

解决方法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);

*链接已死,因为他们弃用了FasterXML / jackson-datatype-jsr310并将其移至jackson-modules-java8。见https://github.com/FasterXML/jackson-modules-java8/issues/76

答案 1 :(得分:2)

我用这个方法解决:

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

对于InstantSerializerWithMilliSecondPrecision,我使用了以下方法:

public class InstantSerializerWithMilliSecondPrecision extends InstantSerializer {

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

现在,即时序列化始终包含毫秒。示例: 2019-09-27T02:59:59.000Z

答案 2 :(得分:1)

Sean Carroll提到的两个变通办法中没有一个有效。最后,我为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);
    }
}

我猜杰克逊use Instant.toString() method to serialize Instant objects默认是。我还找到了some discussions about Instant.toString() method on StackOverflow

答案 3 :(得分:0)

除了可以解决Jackson库的错误外,还可以快速解决以下问题: 在您拥有Timestamp变量的POJO类中创建一个字符串变量:

private Timestamp createTimeStamp;

private String stringCreateTimeStamp;   

将时间戳值捕获为字符串:

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

参考https://www.baeldung.com/java-string-to-timestamp进行转化

答案 4 :(得分:0)

使用针对 LocalDateTime ZonedDateTime 类的自定义序列化程序来解决。

我的解决方案对我有用,因为我在API响应中仅使用了这两个类来表示日期和时间!我不使用“即时”或“日期”,因此请注意。

@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))
    }
}
}