FasterXML / jackson-modules-java8

Set of support modules for Java 8 datatypes (Optionals, date/time) and features (parameter names)
Apache License 2.0
401 stars 117 forks source link

Year deserialization ignores `@JsonFormat` pattern #78

Closed devdevx closed 5 years ago

devdevx commented 6 years ago

Jackson version: 2.9.3 Jackson datatype version: 2.9.6

Example of the @JsonFormat definition:

public class ObjectTest {
   @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "'Y'yyyy")
    private Year customYear;
   // Getters and setters
}

Test example:

ObjectTest object = new ObjectTest();
object.setCustomYear(Year.of(2018));
ObjectMapper objectMapper = new ObjectMapper().registerModule(new JavaTimeModule());
String json = objectMapper.writeValueAsString(object); // OK -> "{\"customYear\":\"Y2018\"}";
object = objectMapper.readValue(json, ObjectTest.class); // ERROR -> Throws exception

Possibly related to: https://github.com/FasterXML/jackson-modules-java8/issues/51

Stack trace:

com.fasterxml.jackson.databind.exc.InvalidFormatException: Cannot deserialize value of type `java.time.Year` from String "Y2018": Failed to deserialize java.time.Year: (java.time.format.DateTimeParseException) Text 'Y2018' could not be parsed at index 0
 at [Source: (String)"{"customYear":"Y2018"}"; line: 1, column: 15] (through reference chain: com.devdevx.examples.jackson.domain.javatime.JavaTime["customYear"])

    at com.fasterxml.jackson.databind.exc.InvalidFormatException.from(InvalidFormatException.java:67)
    at com.fasterxml.jackson.databind.DeserializationContext.weirdStringException(DeserializationContext.java:1548)
    at com.fasterxml.jackson.databind.DeserializationContext.handleWeirdStringValue(DeserializationContext.java:910)
    at com.fasterxml.jackson.datatype.jsr310.deser.JSR310DeserializerBase._handleDateTimeException(JSR310DeserializerBase.java:80)
    at com.fasterxml.jackson.datatype.jsr310.deser.YearDeserializer.deserialize(YearDeserializer.java:64)
    at com.fasterxml.jackson.datatype.jsr310.deser.YearDeserializer.deserialize(YearDeserializer.java:34)
    at com.fasterxml.jackson.databind.deser.impl.MethodProperty.deserializeAndSet(MethodProperty.java:127)
    at com.fasterxml.jackson.databind.deser.BeanDeserializer.vanillaDeserialize(BeanDeserializer.java:287)
    at com.fasterxml.jackson.databind.deser.BeanDeserializer.deserialize(BeanDeserializer.java:151)
    at com.fasterxml.jackson.databind.ObjectMapper._readMapAndClose(ObjectMapper.java:4001)
    at com.fasterxml.jackson.databind.ObjectMapper.readValue(ObjectMapper.java:2992)
    at com.devdevx.examples.jackson.domain.JsonTest.toObject(JsonTest.java:38)
    at com.devdevx.examples.jackson.domain.javatime.JavaTimeTest.customYearJsonToObject(JavaTimeTest.java:279)
    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.platform.commons.util.ReflectionUtils.invokeMethod(ReflectionUtils.java:515)
    at org.junit.jupiter.engine.execution.ExecutableInvoker.invoke(ExecutableInvoker.java:115)
    at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.lambda$invokeTestMethod$6(TestMethodTestDescriptor.java:170)
    at org.junit.jupiter.engine.execution.ThrowableCollector.execute(ThrowableCollector.java:40)
    at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.invokeTestMethod(TestMethodTestDescriptor.java:166)
    at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.execute(TestMethodTestDescriptor.java:113)
    at org.junit.jupiter.engine.descriptor.TestMethodTestDescriptor.execute(TestMethodTestDescriptor.java:58)
    at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$5(NodeTestTask.java:134)
    at org.junit.platform.engine.support.hierarchical.SingleTestExecutor.executeSafely(SingleTestExecutor.java:66)
    at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:128)
    at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:109)
    at java.util.ArrayList.forEach(ArrayList.java:1249)
    at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.invokeAll(SameThreadHierarchicalTestExecutorService.java:38)
    at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$5(NodeTestTask.java:138)
    at org.junit.platform.engine.support.hierarchical.SingleTestExecutor.executeSafely(SingleTestExecutor.java:66)
    at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:128)
    at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:109)
    at java.util.ArrayList.forEach(ArrayList.java:1249)
    at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.invokeAll(SameThreadHierarchicalTestExecutorService.java:38)
    at org.junit.platform.engine.support.hierarchical.NodeTestTask.lambda$executeRecursively$5(NodeTestTask.java:138)
    at org.junit.platform.engine.support.hierarchical.SingleTestExecutor.executeSafely(SingleTestExecutor.java:66)
    at org.junit.platform.engine.support.hierarchical.NodeTestTask.executeRecursively(NodeTestTask.java:128)
    at org.junit.platform.engine.support.hierarchical.NodeTestTask.execute(NodeTestTask.java:109)
    at org.junit.platform.engine.support.hierarchical.SameThreadHierarchicalTestExecutorService.submit(SameThreadHierarchicalTestExecutorService.java:32)
    at org.junit.platform.engine.support.hierarchical.HierarchicalTestExecutor.execute(HierarchicalTestExecutor.java:49)
    at org.junit.platform.engine.support.hierarchical.HierarchicalTestEngine.execute(HierarchicalTestEngine.java:47)
    at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:170)
    at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:154)
    at org.junit.platform.launcher.core.DefaultLauncher.execute(DefaultLauncher.java:90)
    at com.intellij.junit5.JUnit5IdeaTestRunner.startRunnerWithArgs(JUnit5IdeaTestRunner.java:62)
    at com.intellij.rt.execution.junit.IdeaTestRunner$Repeater.startRunnerWithArgs(IdeaTestRunner.java:47)
    at com.intellij.rt.execution.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:242)
    at com.intellij.rt.execution.junit.JUnitStarter.main(JUnitStarter.java:70)
Caused by: java.time.format.DateTimeParseException: Text 'Y2018' could not be parsed at index 0
    at java.time.format.DateTimeFormatter.parseResolved0(DateTimeFormatter.java:1949)
    at java.time.format.DateTimeFormatter.parse(DateTimeFormatter.java:1851)
    at java.time.Year.parse(Year.java:292)
    at java.time.Year.parse(Year.java:277)
    at com.fasterxml.jackson.datatype.jsr310.deser.YearDeserializer.deserialize(YearDeserializer.java:60)
    ... 45 more
devdevx commented 6 years ago

I'm not sure, but it seems to me that com.fasterxml.jackson.datatype.jsr310.deser.YearDeserializer shoud extend JSR310DateTimeDeserializerBase to use the custom pattern. What do you think?

cowtowncoder commented 5 years ago

Ok, so: added tests in 2.10 for all 3 modules, and fixed 2 to be serializable (datatypes, i.e "optionals", parameter names), but jsr310 (date/time) is trickier case. Problem here is that although everything else is or can be made serializable. Java 8 DateTimeFormatter isn't. And although theoretically it is of course possible to work around this that may not be practical.

For 3.0 (master) I can change things so that Module is serializable, but I am not super confident about 2.x. Leaving open for now, regardless.

cowtowncoder commented 5 years ago

I think I re-opened wrong issue. Closing.