Джексон сериализует мгновенный выпуск до наносекундной проблемы - PullRequest
1 голос
/ 28 мая 2019

Jackson сериализует java.time.Instant с WRITE_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.Мне нужна часть секунд и часть дробных миллисекунд.

1 Ответ

1 голос
/ 28 мая 2019

Когда мы работаем с пакетом Java 8 Time и 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)) {
                String concatenated = getEpochSeconds.applyAsLong(value) + "." + getNanoseconds.applyAsInt(value);
                generator.writeNumber(new BigDecimal(concatenated));
                return;
            }
        }

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

И пример, как его использовать:

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 классе.

...