杰克逊:解析自定义偏移日期时间 [英] Jackson: parse custom offset date time

查看:321
本文介绍了杰克逊:解析自定义偏移日期时间的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个具有时间戳属性的模型:

I have a model which has a timestamp property:

class Model {
    @JsonProperty("timestamp")
    private OffsetDateTime timestamp;
}

时间戳的格式如下:

2017-09-17 13:45:42.710576+02

OffsetDateTime 无法解析:


com.fasterxml.jackson.databind.exc.InvalidFormatException:无法从字符串2017-09-17 13:45:42.710576 + 02反序列化类型 java.time.OffsetDateTime 的值:文字'2017-09-17 13:45:42.710576 + 02'无法在索引10解析

com.fasterxml.jackson.databind.exc.InvalidFormatException: Cannot deserialize value of type java.time.OffsetDateTime from String "2017-09-17 13:45:42.710576+02": Text '2017-09-17 13:45:42.710576+02' could not be parsed at index 10

我怎么能解决这个问题?

How can I fix this?

推荐答案

你必须告诉杰克逊日期的格式。基本上,你有年 - 月 - 日后跟小时:分钟:秒。微秒和2位数的偏移量( 02 )。所以你的模式将是:

You must tell Jackson in what format the date is. Basically, you have year-month-day followed by hour:minute:second.microseconds and the offset with 2 digits (+02). So your pattern will be:

@JsonProperty("timestamp")
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss.SSSSSSx")
private OffsetDateTime timestamp;

看看所有日期/时间模式以获得更详细的说明。

Take a look at all the date/time patterns for a more detailed explanation.

如果你想在 OffsetDateTime中保留相同的偏移量( +02 ,不要忘记调整 DeserializationFeature.ADJUST_DATES_TO_CONTEXT_TIME_ZONE 选项 false

如果此选项设置为 true (在我的测试中),结果将转换为UTC(但它实际上会转换为任何时区在Jackson中配置:

If this option is set to true (in my tests), the result is converted to UTC (but it actually converts to whatever timezone is configured in Jackson):


2017-09-17T11:45:42.710576Z

2017-09-17T11:45:42.710576Z

如果我设置为 false ,则使用偏移量输入中的d保留:

If I set to false, the offset used in the input is preserved:


2017-09-17T13:45:42.710576 + 02:00

2017-09-17T13:45:42.710576+02:00






上面的代码适用于小数点后的正好6位数。但如果此数量不同,您可以使用由 [] 分隔的可选模式。

示例:如果输入可以有6或3个十进制数字,我可以使用 pattern =yyyy-MM-dd HH:mm:ss。[SSSSSS] [SSS] x。可选部分 [SSSSSS] [SSS] 告诉解析器要么考虑6位或3位数。

Example: if the input can have 6 or 3 decimal digits, I can use pattern = "yyyy-MM-dd HH:mm:ss.[SSSSSS][SSS]x". The optional sections [SSSSSS] and [SSS] tells the parser to either consider 6 or 3 digits.

可选模式的问题在于,在序列化时,它会打印所有模式(因此它会打印两秒的小数部分:6 3位数。

The problem with optional patterns is that, when serializing, it prints all the patterns (so it will print the fraction of second twice: with 6 and with 3 digits).

另一种方法是创建自定义序列化器和反序列化器(通过扩展 com。 fasterxml.jackson.databind.JsonSerializer com.fasterxml.jackson.databind.JsonDeserializer ):

Another alternative is to create custom serializers and deserializers (by extending com.fasterxml.jackson.databind.JsonSerializer and com.fasterxml.jackson.databind.JsonDeserializer):

public class CustomDeserializer extends JsonDeserializer<OffsetDateTime> {

    private DateTimeFormatter formatter;

    public CustomDeserializer(DateTimeFormatter formatter) {
        this.formatter = formatter;
    }

    @Override
    public OffsetDateTime deserialize(JsonParser parser, DeserializationContext context) throws IOException, JsonProcessingException {
        return OffsetDateTime.parse(parser.getText(), this.formatter);
    }
}

public class CustomSerializer extends JsonSerializer<OffsetDateTime> {

    private DateTimeFormatter formatter;

    public CustomSerializer(DateTimeFormatter formatter) {
        this.formatter = formatter;
    }

    @Override
    public void serialize(OffsetDateTime value, JsonGenerator gen, SerializerProvider provider) throws IOException, JsonProcessingException {
        gen.writeString(value.format(this.formatter));
    }
}

然后你可以在<$ c $中注册那些C> JavaTimeModule 。如何配置这将取决于您正在使用的环境(例如:在Spring中,您可以在 xml中进行配置文件)。我将以编程方式执行此操作。

Then you can register those in the JavaTimeModule. How to configure this will depend on the environment you're using (example: in Spring you can configure in the xml files). I'll just do it programatically as an example.

首先,我使用 java.time.format.DateTimeFormatterBuilder

DateTimeFormatter formatter = new DateTimeFormatterBuilder()
    // date/time
    .appendPattern("yyyy-MM-dd HH:mm:ss")
    // optional fraction of seconds (from 0 to 9 digits)
    .optionalStart().appendFraction(ChronoField.NANO_OF_SECOND, 0, 9, true).optionalEnd()
    // offset
    .appendPattern("x")
    // create formatter
    .toFormatter();

此格式化程序接受0到9位数的可选小数秒。然后我使用上面的自定义类并在 ObjectMapper 中注册它们:

This formatter accepts an optional fraction of second with 0 to 9 digits. Then I use the custom classes above and register them in the ObjectMapper:

// set formatter in the module and register in object mapper
ObjectMapper mapper = new ObjectMapper();
mapper.configure(DeserializationFeature.ADJUST_DATES_TO_CONTEXT_TIME_ZONE, false);
JavaTimeModule module = new JavaTimeModule();
module.addSerializer(OffsetDateTime.class, new CustomSerializer(formatter));
module.addDeserializer(OffsetDateTime.class, new CustomDeserializer(formatter));
mapper.registerModule(module);

我还删除了 @JsonFormat 注释字段:

@JsonProperty("timestamp")
private OffsetDateTime timestamp;

现在它接受的价值如 2017-09-17 13:45: 42 + 02 (无分数秒)和 2017-09-17 13:45:42.71014 + 02 (5位小数)。它可以解析从0到9的十进制数字(9是API支持的最大值),并且在序列化时打印的数量完全相同。

And now it accepts values like 2017-09-17 13:45:42+02 (no fraction of seconds) and 2017-09-17 13:45:42.71014+02 (5 decimal digits). It can parse from 0 to 9 decimal digits (9 is the maximum supported by the API), and it prints exactly the same quantity when serializing.

上面的替代方法非常灵活,因为它允许在自定义类中设置格式化程序。但它也为所有 OffsetDateTime 字段设置了序列化和反序列化。

The alternative above is very flexible as it allows to set the formatter in the custom classes. But it also sets the serialization and deserialization for all OffsetDateTime fields.

如果你不想那样,你也可以创建一个具有固定格式化程序的类:

If you don't want that, you can also create a class with a fixed formatter:

static class CustomDeserializer extends JsonDeserializer<OffsetDateTime> {

    private DateTimeFormatter formatter = // create formatter as above

    // deserialize method is the same
}

static class CustomSerializer extends JsonSerializer<OffsetDateTime> {

    private DateTimeFormatter formatter = // create formatter as above

    // serialize method is the same
}

然后,您可以使用注释 com.fasterxml.jackson.databind.annotation将这些添加到您想要的字段中。 JsonSerialize com.fasterxml.jackson.databind.annotation.JsonDeserialize

Then, you can add those to only the fields you want, using the annotations com.fasterxml.jackson.databind.annotation.JsonSerialize and com.fasterxml.jackson.databind.annotation.JsonDeserialize:

@JsonProperty("timestamp")
@JsonSerialize(using = CustomSerializer.class)
@JsonDeserialize(using = CustomDeserializer.class)
private OffsetDateTime timestamp;

使用此功能,您无需在模块中注册自定义序列化程序,只需注释注释字段将使用自定义类(其他 OffsetDateTime 字段将使用默认设置)。

With this, you don't need to register the custom serializers in the module, and only the annotated field will use the custom classes (the other OffsetDateTime fields will use the default settings).

这篇关于杰克逊:解析自定义偏移日期时间的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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