Jackson 将 Instant 序列化为纳秒问题 [英] Jackson Serialize Instant to Nanosecond Issue

查看:45
本文介绍了Jackson 将 Instant 序列化为纳秒问题的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

Jackson 序列化 java.time.Instant 并默认启用 WRITE_DATE_TIMESTAMPS_AS_NANOOSECONDS.

Jackson serialises java.time.Instant with WRITE_DATE_TIMESTAMPS_AS_NANOSECONDS enabled by default.

它像这样产生JSON

{ "timestamp":1421261297.356000000 }

我想知道是否有办法去掉末尾的零.我想要类似的东西:

I wonder if there's a way to get rid of the zeros at the end. I want something like:

{ "timestamp":1421261297.356 }

我试过了:

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

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

But this configuration changes it to millisecond representation 1421261297356. I want the seconds part and the fractional milliseconds part.

推荐答案

当我们使用 Java 8 Time 包和 Jackson 好想法是使用 jackson-modules-java8 项目服务许多序列化器和反序列化器可供使用.要启用它,我们需要注册 JavaTimeModule 模块.序列化 Instant InstantSerializer 被使用.当我们检查它是如何实现时,我们会发现在幕后 DecimalUtils.toDecimal 方法被使用.看起来总是在纳秒值的末尾添加零.

When we are working with Java 8 Time package and Jackson good idea is to use jackson-modules-java8 project which serves many serialisers and deserialisers ready to use. To enable it we need to register JavaTimeModule module. To serialise Instant InstantSerializer is used. When we check how it is implemented we will find out that behind scene DecimalUtils.toDecimal method is used. It looks like there is always zeros added at the end of nanoseconds value.

我们可以编写我们的 InstantSerializer 以期望的方式序列化它.因为这个项目中的类还没有准备好轻松扩展,我们需要实现许多不需要的方法和构造函数.我们还需要在我们的项目 com.fasterxml.jackson.datatype.jsr310.ser 包中创建并在那里创建我们的实现.见下例:

We can write our InstantSerializer which serialises it in desired way. Because classes in this project are not ready to easily extend we need to implement many unwanted methods and constructors. Also we need create in our project com.fasterxml.jackson.datatype.jsr310.ser package and create our implementation there. See below example:

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');
    }
}

以及如何使用它的示例:

And example how to use it:

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}

如果您想在所有情况下都删除所有零,请编写自己的 getNanoseconds 函数,在 ShortInstantSerializer 类中声明.

If you want to rid of all zeros in all cases write your own getNanoseconds function declared in ShortInstantSerializer class.

这篇关于Jackson 将 Instant 序列化为纳秒问题的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆