一尘不染

杰克逊将即时序列化为纳秒级问题

json

Jackson串行化java.time.InstantWRITE_DATE_TIMESTAMPS_AS_NANOSECONDS默认启用。

它产生JSON像这样

{ "timestamp":1421261297.356000000 }

我想知道是否有一种方法可以消除最后的零。我想要类似的东西:

{ "timestamp":1421261297.356 }

我试过了:

mapper.configure( SerializationFeature.WRITE_DATE_TIMESTAMPS_AS_NANOSECONDS, false );
mapper.configure( SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, true );

但是此配置将其更改为毫秒表示1421261297356。我想要秒部分和小数毫秒部分。


阅读 419

收藏
2020-07-27

共1个答案

一尘不染

当我们使用Java 8 Timepackage时,Jackson最好使用jackson-modules-
java8
项目,该项目可以使用许多序列化程序和反序列化程序。要启用它,我们需要注册JavaTimeModule模块。要序列化Instant
InstantSerializer,请使用。当我们检查它的实现方式时,我们会发现在后台使用了DecimalUtils.toDecimal方法。看起来在纳秒值的末尾总是添加零。

我们可以编写InstantSerializer以所需方式对其进行序列化的代码。由于该项目中的类尚未准备好轻松扩展,因此我们需要实现许多不需要的方法和构造函数。另外,我们需要在项目com.fasterxml.jackson.datatype.jsr310.ser包中创建并在其中创建实现。请参见以下示例:

package com.fasterxml.jackson.datatype.jsr310.ser;

import com.fasterxml.jackson.annotation.JsonFormat;
import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.databind.SerializerProvider;

import java.io.IOException;
import java.math.BigDecimal;
import java.time.Instant;
import java.time.format.DateTimeFormatter;
import java.util.function.ToIntFunction;
import java.util.function.ToLongFunction;

public class ShortInstantSerializer extends InstantSerializerBase<Instant> {

    private ToLongFunction<Instant> getEpochSeconds = Instant::getEpochSecond;
    private ToIntFunction<Instant> getNanoseconds = i -> i.getNano() / 1_000_000;

    public ShortInstantSerializer() {
        super(Instant.class, Instant::toEpochMilli, Instant::getEpochSecond, Instant::getNano, null);
    }

    protected ShortInstantSerializer(ShortInstantSerializer base, Boolean useTimestamp, Boolean useNanoseconds, DateTimeFormatter formatter) {
        super(base, useTimestamp, useNanoseconds, formatter);
    }

    @Override
    protected JSR310FormattedSerializerBase<?> withFormat(Boolean useTimestamp, DateTimeFormatter formatter, JsonFormat.Shape shape) {
        return new ShortInstantSerializer(this, useTimestamp, null, formatter);
    }

    @Override
    public void serialize(Instant value, JsonGenerator generator, SerializerProvider provider) throws IOException {
        if (useTimestamp(provider)) {
            if (useNanoseconds(provider)) {
                generator.writeNumber(new BigDecimal(toShortVersion(value)));
                return;
            }
        }

        super.serialize(value, generator, provider);
    }

    private String toShortVersion(final Instant value) {
        return getEpochSeconds.applyAsLong(value) + "." + padWithZeros(getNanoseconds.applyAsInt(value));
    }

    private String padWithZeros(final int value) {
        return String.format("%1$3s", String.valueOf(value)).replace(' ', '0');
    }
}

并举例说明如何使用它:

import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
import com.fasterxml.jackson.datatype.jsr310.ser.ShortInstantSerializer;

import java.time.Instant;

public class JsonApp {

    public static void main(String[] args) throws Exception {
        JavaTimeModule javaTimeModule = new JavaTimeModule();
        javaTimeModule.addSerializer(Instant.class, new ShortInstantSerializer());

        ObjectMapper mapper = new ObjectMapper();
        mapper.registerModule(javaTimeModule);
        mapper.disable(SerializationFeature.INDENT_OUTPUT);

        System.out.println(mapper.writeValueAsString(new Element()));
    }
}

class Element {

    private Instant timestamp = Instant.now();

    public Instant getTimestamp() {
        return timestamp;
    }

    public void setTimestamp(Instant timestamp) {
        this.timestamp = timestamp;
    }
}

上面的代码打印:

{"timestamp":1559074287.223}

如果要在所有情况下都消除全零,则编写您自己的getNanosecondsShortInstantSerializer类中声明的函数。

2020-07-27