FasterXML / jackson-modules-java8

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

Add `JavaTimeFeature.NORMALIZE_DESERIALIZED_ZONE_ID` to allow disabling ZoneId normalization on deserialization #281

Closed indyana closed 9 months ago

indyana commented 10 months ago

Change in 2.15 to normalize zone when deserializing to ZonedDateTime causes breakage in some applications because normalized time zone does not match configured Jackson time zone. Would be nice to have ObjectMapper configuration that allows for turning normalization on and off.

Details There are many places where we're comparing ZonedDateTime fields deserialized from stored JSON strings (format written out: "2023-02-02T20:23:11.057Z"), to ZonedDateTime objects created in code with ZoneId.of("UTC") . Comparing a ZonedDateTime object created by application code to one deserialized from JSON now no longer works because the zones are not equal. (Zone of the deserialized JSON got normalized to "Z" starting in 2.15 release).

This happens whether relying on Jackson default time zone OR specifically configuring the ObjectMapper / Jackson to use time zone "UTC".

Fixing seems to mean replacing anywhere in code using ZoneId "UTC" with the offset zone Z, but that's a lot of application code to go through.

Notes from comments on issue #267

@indyana If you'd like to see configurability, please file a new issue as RFE, asking for configurability, referencing back to this issue. Then if anyone has time and interest they could work on adding this feature -- it does sound useful.

One practical complication here is just that module does not yet have configurability, so would probably need to add a JavaTimeModule.Feature enum and a bit of scaffolding. Aside from that should be quite straight-forward.

Originally posted by @cowtowncoder in https://github.com/FasterXML/jackson-modules-java8/issues/267#issuecomment-1761969124

cowtowncoder commented 9 months ago

@indyana I was able to implement this: configuration is via JavaTimeModule, like so:

ObjectMapper mapper = JsonMapper.builder()
            .addModule(new JavaTimeModule().disable(JavaTimeFeature.NORMALIZE_DESERIALIZED_ZONE_ID))
            .build();

I added just one test to verify and am not super happy with it, so I hope someone else can verify its functioning. But implementation of actual normalization disabling in straight-forward enough so hoping it works as expected.

indyana commented 9 months ago

Great, thanks for considering that additional configuration feature! I'm sure I'm not the only one that will run into this time zone vs offset confusion, so will be good for users to be able to decide what behavior suits their application.

cowtowncoder commented 9 months ago

@indyana Yeah, thank you for suggesting it! And like I said, if there's any way you could try it out (need to build/use 2.16.0-SNAPSHOT until 2.16.0 release is out; this was not part of 2.16.0-rc1) to verify it works as it should, that'd be great.

indyana commented 9 months ago

Confirmed that pulling 2.16.0-SNAPSHOT from Sonatype and adding disable(JavaTimeFeature.NORMALIZE_DESERIALIZED_ZONE_ID) correctly reverts ZonedDateTime objects to UTC again (vs Z), and our unit tests pass.

cowtowncoder commented 9 months ago

Thank you @indyana , much appreciated!