Jackson 自定义即时从 ISO8601 字符串反序列化,不带 Z
我需要将 ISO 8601 值反序列化为 Instant,但该字符串没有尾随 Z 字符。
例如,
2022-03-01T15:42:23.800
而不是
2022-03-01T15:42:23.800Z
这些是我的测试:
public class JacksonParsingTests {
private static ObjectMapper objectMapper;
@BeforeClass
public static void setUp(){
objectMapper = new ObjectMapper();
objectMapper.enable(SerializationFeature.INDENT_OUTPUT);
objectMapper.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS);
objectMapper.registerModule(new Jdk8Module());
objectMapper.registerModule(new JavaTimeModule());
}
@Test
public void testInstantSerializationFormat(){
try {
String instantJSON = objectMapper.writeValueAsString(Instant.now());
System.out.println("Instant JSON:");
System.out.println(instantJSON);
} catch (JsonProcessingException e) {
e.printStackTrace();
}
}
@Test
public void testInstantDeserialization() {
try {
String iso8601JSON = "\"2022-03-01T15:42:23.800Z\"";
Instant now = objectMapper.readValue(iso8601JSON, Instant.class);
System.out.println("Zulu ISO8601 deserialization:");
System.out.println(now);
} catch (Exception e) {
e.printStackTrace();
}
}
@Test
public void testCustomInstantDeserialization(){
try {
String customISO8601JSON = "\"2022-03-01T15:42:23.800\"";
Instant now = objectMapper.readValue(customISO8601JSON, Instant.class);
System.out.println("No Zulu ISO8601 deserialization:");
System.out.println(now);
} catch (Exception e) {
e.printStackTrace();
}
}
}
如何为 Instant 类定义自定义反序列化器并将其注册到 ObjectMapper?
我尝试过
public class ISO8601InstantDeserializer extends InstantDeserializer<Instant> {
public ISO8601InstantDeserializer() {
super(InstantDeserializer.INSTANT, new DateTimeFormatterBuilder()
.parseCaseInsensitive()
.append(DateTimeFormatter.ISO_LOCAL_DATE_TIME)
.optionalStart().appendOffset("+HH:MM", "+00:00").optionalEnd()
.optionalStart().appendOffset("+HHMM", "+0000").optionalEnd()
.optionalStart().appendOffset("+HH", "Z").optionalEnd()
.toFormatter());
}
}
但
@BeforeClass
public static void setUp(){
objectMapper = new ObjectMapper();
objectMapper.enable(SerializationFeature.INDENT_OUTPUT);
objectMapper.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS);
objectMapper.registerModule(new Jdk8Module());
objectMapper.registerModule(new JavaTimeModule().addDeserializer(Instant.class, new ISO8601InstantDeserializer()));
}
没有成功。
我得到的错误是:
com.fasterxml.jackson.databind.JsonMappingException: Failed to deserialize java.time.Instant: (java.time.DateTimeException) Unable to obtain Instant from TemporalAccessor: {},ISO resolved to 2022-03-01T15:42:23.800 of type java.time.format.Parsed
at [Source: "2022-03-01T15:42:23.800"; line: 1, column: 1]
at com.fasterxml.jackson.databind.JsonMappingException.from(JsonMappingException.java:277)
at com.fasterxml.jackson.datatype.jsr310.deser.JSR310DeserializerBase._rethrowDateTimeException(JSR310DeserializerBase.java:82)
at com.fasterxml.jackson.datatype.jsr310.deser.InstantDeserializer.deserialize(InstantDeserializer.java:208)
at com.fasterxml.jackson.datatype.jsr310.deser.InstantDeserializer.deserialize(InstantDeserializer.java:48)
at com.fasterxml.jackson.databind.ObjectMapper._readMapAndClose(ObjectMapper.java:3814)
at com.fasterxml.jackson.databind.ObjectMapper.readValue(ObjectMapper.java:2858)
at eu.config.jackson.JacksonParsingTests.testCustomInstantDeserialization(JacksonParsingTests.java:60)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:50)
at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:47)
at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:325)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:78)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:57)
at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290)
at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71)
at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)
at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58)
at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268)
at org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:26)
at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
at org.junit.runner.JUnitCore.run(JUnitCore.java:137)
at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:69)
at com.intellij.rt.junit.IdeaTestRunner$Repeater.startRunnerWithArgs(IdeaTestRunner.java:33)
at com.intellij.rt.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:235)
at com.intellij.rt.junit.JUnitStarter.main(JUnitStarter.java:54)
Caused by: java.time.DateTimeException: Unable to obtain Instant from TemporalAccessor: {},ISO resolved to 2022-03-01T15:42:23.800 of type java.time.format.Parsed
at java.time.Instant.from(Instant.java:378)
at com.fasterxml.jackson.datatype.jsr310.deser.InstantDeserializer.deserialize(InstantDeserializer.java:203)
... 27 more
Caused by: java.time.temporal.UnsupportedTemporalTypeException: Unsupported field: InstantSeconds
at java.time.format.Parsed.getLong(Parsed.java:203)
at java.time.Instant.from(Instant.java:373)
... 28 more
I need to deserialize a ISO 8601 value into an Instant, but the string is without the trailing Z character.
E.g.
2022-03-01T15:42:23.800
instead of
2022-03-01T15:42:23.800Z
These are my tests:
public class JacksonParsingTests {
private static ObjectMapper objectMapper;
@BeforeClass
public static void setUp(){
objectMapper = new ObjectMapper();
objectMapper.enable(SerializationFeature.INDENT_OUTPUT);
objectMapper.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS);
objectMapper.registerModule(new Jdk8Module());
objectMapper.registerModule(new JavaTimeModule());
}
@Test
public void testInstantSerializationFormat(){
try {
String instantJSON = objectMapper.writeValueAsString(Instant.now());
System.out.println("Instant JSON:");
System.out.println(instantJSON);
} catch (JsonProcessingException e) {
e.printStackTrace();
}
}
@Test
public void testInstantDeserialization() {
try {
String iso8601JSON = "\"2022-03-01T15:42:23.800Z\"";
Instant now = objectMapper.readValue(iso8601JSON, Instant.class);
System.out.println("Zulu ISO8601 deserialization:");
System.out.println(now);
} catch (Exception e) {
e.printStackTrace();
}
}
@Test
public void testCustomInstantDeserialization(){
try {
String customISO8601JSON = "\"2022-03-01T15:42:23.800\"";
Instant now = objectMapper.readValue(customISO8601JSON, Instant.class);
System.out.println("No Zulu ISO8601 deserialization:");
System.out.println(now);
} catch (Exception e) {
e.printStackTrace();
}
}
}
How can I define a custom deserializer for the Instant class and register it with the ObjectMapper?
I tried with
public class ISO8601InstantDeserializer extends InstantDeserializer<Instant> {
public ISO8601InstantDeserializer() {
super(InstantDeserializer.INSTANT, new DateTimeFormatterBuilder()
.parseCaseInsensitive()
.append(DateTimeFormatter.ISO_LOCAL_DATE_TIME)
.optionalStart().appendOffset("+HH:MM", "+00:00").optionalEnd()
.optionalStart().appendOffset("+HHMM", "+0000").optionalEnd()
.optionalStart().appendOffset("+HH", "Z").optionalEnd()
.toFormatter());
}
}
and
@BeforeClass
public static void setUp(){
objectMapper = new ObjectMapper();
objectMapper.enable(SerializationFeature.INDENT_OUTPUT);
objectMapper.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS);
objectMapper.registerModule(new Jdk8Module());
objectMapper.registerModule(new JavaTimeModule().addDeserializer(Instant.class, new ISO8601InstantDeserializer()));
}
but without success.
The error I get is:
com.fasterxml.jackson.databind.JsonMappingException: Failed to deserialize java.time.Instant: (java.time.DateTimeException) Unable to obtain Instant from TemporalAccessor: {},ISO resolved to 2022-03-01T15:42:23.800 of type java.time.format.Parsed
at [Source: "2022-03-01T15:42:23.800"; line: 1, column: 1]
at com.fasterxml.jackson.databind.JsonMappingException.from(JsonMappingException.java:277)
at com.fasterxml.jackson.datatype.jsr310.deser.JSR310DeserializerBase._rethrowDateTimeException(JSR310DeserializerBase.java:82)
at com.fasterxml.jackson.datatype.jsr310.deser.InstantDeserializer.deserialize(InstantDeserializer.java:208)
at com.fasterxml.jackson.datatype.jsr310.deser.InstantDeserializer.deserialize(InstantDeserializer.java:48)
at com.fasterxml.jackson.databind.ObjectMapper._readMapAndClose(ObjectMapper.java:3814)
at com.fasterxml.jackson.databind.ObjectMapper.readValue(ObjectMapper.java:2858)
at eu.config.jackson.JacksonParsingTests.testCustomInstantDeserialization(JacksonParsingTests.java:60)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:50)
at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:47)
at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:325)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:78)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:57)
at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290)
at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71)
at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)
at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58)
at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268)
at org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:26)
at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
at org.junit.runner.JUnitCore.run(JUnitCore.java:137)
at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:69)
at com.intellij.rt.junit.IdeaTestRunner$Repeater.startRunnerWithArgs(IdeaTestRunner.java:33)
at com.intellij.rt.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:235)
at com.intellij.rt.junit.JUnitStarter.main(JUnitStarter.java:54)
Caused by: java.time.DateTimeException: Unable to obtain Instant from TemporalAccessor: {},ISO resolved to 2022-03-01T15:42:23.800 of type java.time.format.Parsed
at java.time.Instant.from(Instant.java:378)
at com.fasterxml.jackson.datatype.jsr310.deser.InstantDeserializer.deserialize(InstantDeserializer.java:203)
... 27 more
Caused by: java.time.temporal.UnsupportedTemporalTypeException: Unsupported field: InstantSeconds
at java.time.format.Parsed.getLong(Parsed.java:203)
at java.time.Instant.from(Instant.java:373)
... 28 more
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论