杰克逊:解析自定义偏移日期时间
我有具有timestamp属性的模型:杰克逊:解析自定义偏移日期时间
class Model {
@JsonProperty("timestamp")
private OffsetDateTime timestamp;
}
时间戳的格式如下:
2017-09-17 13:45:42.710576+02
OffsetDateTime
无法解析此:
com.fasterxml.jackson.databind.exc.InvalidFormatException:无法反序列化
java.time.OffsetDateTime
类型的值从字符串“2017-09-17 13:45:42.710576 + 02”:文本'2017-09-17 13:45:42.710576 + 02'无法在索引10处解析
我该如何解决此问题?
你必须告诉杰克逊日期是什么格式。基本上,你有year-month-day
其次是hour:minute:second.microseconds
和2位数的偏移量(+02
)。所以你的模式将是:
@JsonProperty("timestamp")
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss.SSSSSSx")
private OffsetDateTime timestamp;
看看all the date/time patterns的更详细的解释。
如果你想保留相同的OffsetDateTime
偏移(+02
),不要忘记调整DeserializationFeature.ADJUST_DATES_TO_CONTEXT_TIME_ZONE
option到false
。
如果此选项设置为true
(在我的测试),结果被转换为UTC(但它实际上转换到任何时区在杰克逊配置):
2017-09-17T11:45 :42.710576Z
如果我设置为false
,偏移量在输入中使用被保留:
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位数字。
可选模式的问题在于,在序列化时,它会打印所有模式(因此它将打印两秒的小数部分:带有3位数的6 和)。
另一种方法是(通过延伸com.fasterxml.jackson.databind.JsonSerializer
和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));
}
}
然后,可以注册那些在JavaTimeModule
。如何配置这将取决于您使用的环境(例如:在Spring中,您可以在xml files中进行配置)。我将以编程方式作为示例。
首先创建格式化器,使用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
注册它们:
// 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支持的最大值),并且在序列化时打印完全相同的数量。
上面的替代方法非常灵活,因为它允许在自定义类中设置格式器。但它也为所有OffsetDateTime
字段设置序列化和反序列化。
如果你不希望出现这种情况,你也可以创建一个类有固定格式:
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
:
@JsonProperty("timestamp")
@JsonSerialize(using = CustomSerializer.class)
@JsonDeserialize(using = CustomDeserializer.class)
private OffsetDateTime timestamp;
有了这个,你不需要在模块中注册自定义序列化,只有注解的字段将使用自定义类(其他OffsetDateTime
字段将使用默认设置)。
有趣的是,我不知道你可以像这样定义日期格式。我应该使用'ZonedDateTime'的'OffsetDateTime'吗? –
@KwersT如果你只有偏移+02,我建议OffsetDateTime。如果存在时区名称(例如欧洲/伦敦)和夏令时规则,请使用ZonedDateTime –
谢谢,这很好。 –