Jackson , java.time , ISO 8601 , 无毫秒序列化

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/40487656/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-11-03 05:15:53  来源:igfitidea点击:

Hymanson , java.time , ISO 8601 , serialize without milliseconds

javaHymansonjava-timeHymanson-modulesHymanson2

提问by Benjamin M

I'm using Hymanson 2.8 and need to communicate with an API that doesn't allow milliseconds within ISO 8601 timestamps.

我正在使用 Hymanson 2.8 并且需要与一个不允许在 ISO 8601 时间戳内出现毫秒的 API 进行通信。

The expected format is this: "2016-12-24T00:00:00Z"

预期的格式是这样的: "2016-12-24T00:00:00Z"

I'm using Hymanson's JavaTimeModule with WRITE_DATES_AS_TIMESTAMPSset to false.

我正在使用 Hymanson 的 JavaTimeModule 并WRITE_DATES_AS_TIMESTAMPS设置为false.

But this will print milliseconds.

但这将打印毫秒。

So I tried to use objectMapper.setDateFormatwhich didn't change anything.

所以我尝试使用objectMapper.setDateFormat它并没有改变任何东西。

My current workaround is this:

我目前的解决方法是这样的:

ObjectMapper om = new ObjectMapper();

DateTimeFormatter dtf = new DateTimeFormatterBuilder()
    .appendInstant(0)
    .toFormatter();

JavaTimeModule jtm = new JavaTimeModule();
jtm.addSerializer(Instant.class, new JsonSerializer<Instant>() {
    @Override
    public void serialize(Instant value, JsonGenerator gen, SerializerProvider serializers) throws IOException, JsonProcessingException {
        gen.writeString(dtf.format(value));
    }
});

om.registerModule(jtm);

I'm overriding the default serializer for Instant.classwhich works.

我正在覆盖适用的默认序列化程序Instant.class



Is there any nice way using some configuration parameter to solve this?

有什么好的方法可以使用一些配置参数来解决这个问题吗?

采纳答案by Pau

Update:

更新:

Just add a @JsonFormatannotation whith the date format above the Instantproperty. It's very easy.

只需@JsonFormatInstant属性上方添加带有日期格式的注释即可。这很容易。

In the case you have an ObjectMapper with the JavaTimeModulelike next:

如果您有一个 ObjectMapper,如下JavaTimeModule所示:

ObjectMapper mapper = new ObjectMapper();
mapper.registerModule(new JavaTimeModule());

If you have a class with an Instantproperty, you should add the @JsonFormatannotation and put the date pattern which hasn't milliseconds. It would be like next:

如果你有一个带有Instant属性的类,你应该添加@JsonFormat注释并放置没有毫秒的日期模式。它会像下一个:

public static class TestDate {

    @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd hh:mm:ss", timezone = "UTC")
    Instant instant;

    //getters & setters
}

So if you serialize an object to Json it works perfectly:

因此,如果您将对象序列化为 Json,它可以完美运行:

String json = mapper.writeValueAsString(testDate);
System.out.println(json); 

Output

输出

{"instant":"2016-11-10 06:03:06"}

{“即时”:“2016-11-10 06:03:06”}



Old Answer. I don't know why but It doesn't work propertly:

旧答案。我不知道为什么,但它不能正常工作:

You could use the Hymanson2ObjectMapperBuilderto build it.

您可以使用Hymanson2ObjectMapperBuilder来构建它。

You just need to add the dateFormat you want. It would be something like next:

您只需要添加所需的 dateFormat。接下来是这样的:

DateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss");

ObjectMapper mapper = Hymanson2ObjectMapperBuilder
            .json()       
            .featuresToDisable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS) 
            .modules(new JavaTimeModule())
            .dateFormat(dateFormat)
            .build();

回答by Sagar Veeram

Here is an alternative which is something you can set globally, but will need you to use ZonedDateTimewith instant formatter as we can't set the format for the InstantSerializer provided with Java Time Module.

这是您可以全局设置的替代方法,但需要您ZonedDateTime与即时格式化程序一起使用,因为我们无法为InstantJava 时间模块提供的序列化程序设置格式。

You wont see any side effects of using zoned date time for instant as Hymanson serializes the zone id separately and is disabled by default. So technically, this is similar to applying the formatter to Instant.

您不会看到立即使用分区日期时间的任何副作用,因为 Hymanson 单独序列化区域 ID 并且默认情况下禁用。所以从技术上讲,这类似于将格式化程序应用于Instant.

When used this way, the ZonedDateTimeserializer delegates the serialization to InstantBaseSerializerand uses the specified custom format.

以这种方式使用时,ZonedDateTime序列化程序将序列化委托给InstantBaseSerializer并使用指定的自定义格式。

@RunWith(JUnit4.class)
public class InstantNoMillisTest {

    private ObjectMapper objectMapper;

    @Before
    public void init() {
        JavaTimeModule module = new JavaTimeModule();
        ZonedDateTimeSerializer zonedDateTimeSerializer = new ZonedDateTimeSerializer(new DateTimeFormatterBuilder().appendInstant(0).toFormatter());
        module.addSerializer(ZonedDateTime.class, zonedDateTimeSerializer);
        module.addDeserializer(ZonedDateTime.class, InstantDeserializer.ZONED_DATE_TIME);

        objectMapper = Hymanson2ObjectMapperBuilder.json()
                .modules(module)
                .featuresToDisable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS)
                .build();
    }

    @Test
    public void serialize() throws IOException {
        ZonedDateTime zonedDateTime = ZonedDateTime.now();
        String noMillis = objectMapper.writeValueAsString(zonedDateTime);
        System.out.print(noMillis);
    }

    @Test
    public void deserialize() throws IOException {
        String dateTime = "\"2017-10-26T12:54:59Z\"";
        ZonedDateTime noMillis = objectMapper.readValue(dateTime, ZonedDateTime.class);
        System.out.print(noMillis);
    }
}

回答by ZZ 5

Here's some Kotlin code of formatting Instantfields, so they will not contain milliseconds, you can use custom date formatters

这是格式化Instant字段的一些 Kotlin 代码,因此它们不会包含毫秒,您可以使用自定义日期格式化程序

ObjectMapper().apply {
        val javaTimeModule = JavaTimeModule()
        javaTimeModule.addSerializer(Instant::class.java, Iso8601WithoutMillisInstantSerializer())
        registerModule(javaTimeModule)
        disable(WRITE_DATES_AS_TIMESTAMPS)
    }

private class Iso8601WithoutMillisInstantSerializer
        : InstantSerializer(InstantSerializer.INSTANCE, false, DateTimeFormatterBuilder().appendInstant(0).toFormatter())