Kwe*_*s T 6 java datetime jackson datetime-parsing java-time
我有一个具有时间戳属性的模型:
class Model {
@JsonProperty("timestamp")
private OffsetDateTime timestamp;
}
Run Code Online (Sandbox Code Playgroud)
时间戳的格式如下:
2017-09-17 13:45:42.710576+02
Run Code Online (Sandbox Code Playgroud)
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处解析
我怎样才能解决这个问题?
小智 12
你必须告诉杰克逊日期的格式.基本上,你year-month-day跟着hour:minute:second.microseconds和2位数的偏移(+02).所以你的模式将是:
@JsonProperty("timestamp")
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss.SSSSSSx")
private OffsetDateTime timestamp;
Run Code Online (Sandbox Code Playgroud)
查看所有日期/时间模式以获得更详细的说明.
如果要保留相同的offset(+02)OffsetDateTime,请不要忘记将DeserializationFeature.ADJUST_DATES_TO_CONTEXT_TIME_ZONE选项调整为false.
如果此选项设置为true(在我的测试中),结果将转换为UTC(但它实际上转换为在Jackson中配置的任何时区):
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位数.
可选模式的问题在于,在序列化时,它会打印所有模式(因此它将打印两秒的小数部分:6 和 3位数).
另一种方法是创建自定义序列化器和反序列化器(通过扩展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));
}
}
Run Code Online (Sandbox Code Playgroud)
然后你可以注册那些JavaTimeModule.如何配置这将取决于您正在使用的环境(例如:在Spring中,您可以在xml文件中进行配置).我将以编程方式作为示例.
首先我创建格式化程序,使用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();
Run Code Online (Sandbox Code Playgroud)
此格式化程序接受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);
Run Code Online (Sandbox Code Playgroud)
我还@JsonFormat从字段中删除了注释:
@JsonProperty("timestamp")
private OffsetDateTime timestamp;
Run Code Online (Sandbox Code Playgroud)
现在它接受的值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
}
Run Code Online (Sandbox Code Playgroud)
然后,您可以使用注释将这些添加到您想要的字段中,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;
Run Code Online (Sandbox Code Playgroud)
这样,您不需要在模块中注册自定义序列化程序,只有带注释的字段将使用自定义类(其他OffsetDateTime字段将使用默认设置).
| 归档时间: |
|
| 查看次数: |
6765 次 |
| 最近记录: |