当前位置: 首页 > 知识库问答 >
问题:

Jackson序列化即时到纳秒问题

彭嘉赐
2023-03-14

Jackson序列化java.time。默认情况下,即时,将日期时间戳写入为纳秒。

它产生这样的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。我想要秒部分和小数毫秒部分。

共有2个答案

微生雨泽
2023-03-14

我采纳了上面Michal的想法,并将现有的com.fasterxml.jackson.datatype.jsr310. DecimalUtils#toBigDecimal(长秒,int纳秒)封装在序列化器中

class ShortInstantSerializer extends StdSerializer<Instant> {
    ShortInstantSerializer() {
        super(Instant.class);
    }

    @Override
    public void serialize(Instant value, JsonGenerator gen, SerializerProvider provider) throws IOException {
        gen.writeNumber(DecimalUtils.toBigDecimal(value.getEpochSecond(), value.getNano()));
    }
}

此外,如果您打算在某个时候重新读取它,则该值将反序列化为Double。要返回请执行此操作(感谢inverwebs!)

public static Instant toInstant(Double d) {
    long seconds = d.longValue();
    long micros = Math.round((d - seconds) * 1_000_000);
    return Instant.ofEpochSecond(seconds).plus(micros , ChronoUnit.MICROS);
}
巫马炫明
2023-03-14

当我们使用Java 8包和Jackson时,好主意是使用Jackson-modules-java8项目,该项目为许多可供使用的序列化程序和反序列化程序提供服务。为了启用它,我们需要注册JavaTimeModule。要序列化即时,使用串行化器。当我们检查它是如何实现的时,我们会发现幕后的小数位数。使用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}

如果您想在所有情况下去掉所有零,请编写自己的函数,该函数在ShortInstantSerializer类中声明。

 类似资料:
  • 问题内容: 串行化与默认启用。 它产生像这样 我想知道是否有一种方法可以消除最后的零。我想要类似的东西: 我试过了: 但是此配置将其更改为毫秒表示。我想要秒部分和小数毫秒部分。 问题答案: 当我们使用 package时,最好使用jackson-modules- java8 项目,该项目可以使用许多序列化程序和反序列化程序。要启用它,我们需要注册模块。要序列化 InstantSerializer,请

  • 对于某些用例,我需要将一个POJO转换为另一个具有不同字段名称的POJO。我试着使用Jackson对象映射器。它在某些方面起了作用。然而,最终的结果并不是我所期望的。 如果运行,输出将是: SOUT:UserMap{name_new='Deepak',meta=address::Singapore,id::111} 杰克逊:{“姓名”:“迪帕克”,“地址”:“新加坡”,“身份证”:“111”} 我

  • 问题内容: 我有一些以秒为单位的时间戳(即Unix时间戳)的JSON: 要求Jackson将其反序列化为带有DateTime字段的对象作为时间戳,结果是在该时间段后不久的某个时间,因为Jackson假设它以 毫秒为单位 。除了撕开JSON并添加一些零外,我如何让Jackson理解 秒 时间戳? 问题答案: 我编写了一个自定义反序列化器,以秒为单位处理时间戳(Groovy语法)。 然后,我注释了PO

  • null Spring Boot 1.3.1 Jackson 2.6.4(包含JSR310模块) 这需要自定义反序列化类吗?

  • 我正试图为我的项目标准化时间戳格式,其中源以微秒精度报告。我试图找出是否有一种干净的或者最小化的方法,不需要使用手写的常量。

  • 问题内容: 我使用以下代码来序列化从外部服务获得的响应,并作为我的服务的一部分返回json响应。但是,当外部服务返回带有时区(10:30:00.000-05.00)的时间值时,杰克逊会将其转换为15:30:00。如何忽略时区值? 问题答案: 您可以创建自定义解串器 告诉杰克逊使用您的自定义解串器 并像这样使用它: 您可以使用Jackson自定义序列化为服务响应添加时区信息