Skip to content

Commit 734973b

Browse files
authored
Fix #281: support new JavaTimeFeature.NORMALIZE_DESERIALIZED_ZONE_ID (#285)
1 parent 79d0379 commit 734973b

File tree

4 files changed

+67
-7
lines changed

4 files changed

+67
-7
lines changed

datetime/src/main/java/com/fasterxml/jackson/datatype/jsr310/JavaTimeModule.java

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -121,9 +121,13 @@ public void setupModule(SetupContext context) {
121121

122122
SimpleDeserializers desers = new SimpleDeserializers();
123123
// // Instant variants:
124-
desers.addDeserializer(Instant.class, InstantDeserializer.INSTANT);
125-
desers.addDeserializer(OffsetDateTime.class, InstantDeserializer.OFFSET_DATE_TIME);
126-
desers.addDeserializer(ZonedDateTime.class, InstantDeserializer.ZONED_DATE_TIME);
124+
desers.addDeserializer(Instant.class,
125+
InstantDeserializer.INSTANT.withFeatures(_features));
126+
desers.addDeserializer(OffsetDateTime.class,
127+
InstantDeserializer.OFFSET_DATE_TIME.withFeatures(_features));
128+
desers.addDeserializer(ZonedDateTime.class,
129+
InstantDeserializer.ZONED_DATE_TIME.withFeatures(_features));
130+
127131
// // Other deserializers
128132
desers.addDeserializer(Duration.class, DurationDeserializer.INSTANCE);
129133
desers.addDeserializer(LocalDateTime.class, LocalDateTimeDeserializer.INSTANCE);

datetime/src/main/java/com/fasterxml/jackson/datatype/jsr310/deser/InstantDeserializer.java

Lines changed: 35 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -21,10 +21,12 @@
2121
import com.fasterxml.jackson.core.JsonToken;
2222
import com.fasterxml.jackson.core.JsonTokenId;
2323
import com.fasterxml.jackson.core.io.NumberInput;
24+
import com.fasterxml.jackson.core.util.JacksonFeatureSet;
2425
import com.fasterxml.jackson.databind.BeanProperty;
2526
import com.fasterxml.jackson.databind.DeserializationContext;
2627
import com.fasterxml.jackson.databind.DeserializationFeature;
2728
import com.fasterxml.jackson.datatype.jsr310.DecimalUtils;
29+
import com.fasterxml.jackson.datatype.jsr310.JavaTimeFeature;
2830

2931
import java.io.IOException;
3032
import java.math.BigDecimal;
@@ -54,6 +56,8 @@ public class InstantDeserializer<T extends Temporal>
5456
{
5557
private static final long serialVersionUID = 1L;
5658

59+
private final static boolean DEFAULT_NORMALIZE_ZONE_ID = JavaTimeFeature.NORMALIZE_DESERIALIZED_ZONE_ID.enabledByDefault();
60+
5761
/**
5862
* Constants used to check if ISO 8601 time string is colonless. See [jackson-modules-java8#131]
5963
*
@@ -68,7 +72,7 @@ public class InstantDeserializer<T extends Temporal>
6872
a -> Instant.ofEpochSecond(a.integer, a.fraction),
6973
null,
7074
true, // yes, replace zero offset with Z
71-
true // default: yes, normalize ZoneId
75+
DEFAULT_NORMALIZE_ZONE_ID
7276
);
7377

7478
public static final InstantDeserializer<OffsetDateTime> OFFSET_DATE_TIME = new InstantDeserializer<>(
@@ -78,7 +82,7 @@ public class InstantDeserializer<T extends Temporal>
7882
a -> OffsetDateTime.ofInstant(Instant.ofEpochSecond(a.integer, a.fraction), a.zoneId),
7983
(d, z) -> (d.isEqual(OffsetDateTime.MIN) || d.isEqual(OffsetDateTime.MAX) ? d : d.withOffsetSameInstant(z.getRules().getOffset(d.toLocalDateTime()))),
8084
true, // yes, replace zero offset with Z
81-
true // default: yes, normalize ZoneId
85+
DEFAULT_NORMALIZE_ZONE_ID
8286
);
8387

8488
public static final InstantDeserializer<ZonedDateTime> ZONED_DATE_TIME = new InstantDeserializer<>(
@@ -88,7 +92,7 @@ public class InstantDeserializer<T extends Temporal>
8892
a -> ZonedDateTime.ofInstant(Instant.ofEpochSecond(a.integer, a.fraction), a.zoneId),
8993
ZonedDateTime::withZoneSameInstant,
9094
false, // keep zero offset and Z separate since zones explicitly supported
91-
true // default: yes, normalize ZoneId
95+
DEFAULT_NORMALIZE_ZONE_ID
9296
);
9397

9498
protected final Function<FromIntegerArguments, T> fromMilliseconds;
@@ -212,6 +216,26 @@ protected InstantDeserializer(InstantDeserializer<T> base,
212216
_normalizeZoneId = base._normalizeZoneId;
213217
}
214218

219+
/**
220+
* @since 2.16
221+
*/
222+
@SuppressWarnings("unchecked")
223+
protected InstantDeserializer(InstantDeserializer<T> base,
224+
JacksonFeatureSet<JavaTimeFeature> features)
225+
{
226+
super((Class<T>) base.handledType(), base._formatter);
227+
parsedToValue = base.parsedToValue;
228+
fromMilliseconds = base.fromMilliseconds;
229+
fromNanoseconds = base.fromNanoseconds;
230+
adjust = base.adjust;
231+
replaceZeroOffsetAsZ = base.replaceZeroOffsetAsZ;
232+
_adjustToContextTZOverride = base._adjustToContextTZOverride;
233+
_readTimestampsAsNanosOverride = base._readTimestampsAsNanosOverride;
234+
235+
_normalizeZoneId = features.isEnabled(JavaTimeFeature.NORMALIZE_DESERIALIZED_ZONE_ID);
236+
237+
}
238+
215239
@Override
216240
protected InstantDeserializer<T> withDateFormat(DateTimeFormatter dtf) {
217241
if (dtf == _formatter) {
@@ -225,6 +249,14 @@ protected InstantDeserializer<T> withLeniency(Boolean leniency) {
225249
return new InstantDeserializer<>(this, _formatter, leniency);
226250
}
227251

252+
// @since 2.16
253+
public InstantDeserializer<T> withFeatures(JacksonFeatureSet<JavaTimeFeature> features) {
254+
if (_normalizeZoneId == features.isEnabled(JavaTimeFeature.NORMALIZE_DESERIALIZED_ZONE_ID)) {
255+
return this;
256+
}
257+
return new InstantDeserializer<>(this, features);
258+
}
259+
228260
@SuppressWarnings("unchecked")
229261
@Override // @since 2.12.1
230262
protected JSR310DateTimeDeserializerBase<?> _withFormatOverrides(DeserializationContext ctxt,

datetime/src/test/java/com/fasterxml/jackson/datatype/jsr310/deser/ZonedDateTimeDeserTest.java

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,9 @@
99
import com.fasterxml.jackson.databind.ObjectMapper;
1010
import com.fasterxml.jackson.databind.ObjectReader;
1111
import com.fasterxml.jackson.databind.exc.MismatchedInputException;
12+
import com.fasterxml.jackson.databind.json.JsonMapper;
13+
import com.fasterxml.jackson.datatype.jsr310.JavaTimeFeature;
14+
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
1215
import com.fasterxml.jackson.datatype.jsr310.ModuleTestBase;
1316

1417
import org.junit.Test;
@@ -21,6 +24,7 @@
2124
import java.time.format.DateTimeFormatter;
2225
import java.time.format.DateTimeParseException;
2326
import java.util.Map;
27+
import java.util.TimeZone;
2428

2529
import static org.junit.Assert.assertEquals;
2630
import static org.junit.Assert.assertNull;
@@ -29,6 +33,12 @@
2933
public class ZonedDateTimeDeserTest extends ModuleTestBase
3034
{
3135
private final ObjectReader READER = newMapper().readerFor(ZonedDateTime.class);
36+
37+
private final ObjectReader READER_NON_NORMALIZED_ZONEID = JsonMapper.builder()
38+
.addModule(new JavaTimeModule().disable(JavaTimeFeature.NORMALIZE_DESERIALIZED_ZONE_ID))
39+
.build()
40+
.readerFor(ZonedDateTime.class);
41+
3242
private final TypeReference<Map<String, ZonedDateTime>> MAP_TYPE_REF = new TypeReference<Map<String, ZonedDateTime>>() { };
3343

3444
static class WrapperWithFeatures {
@@ -57,13 +67,24 @@ public WrapperWithReadTimestampsAsNanosEnabled() { }
5767
}
5868

5969
@Test
60-
public void testDeserializationAsString01() throws Exception
70+
public void testDeserFromString() throws Exception
6171
{
6272
assertEquals("The value is not correct.",
6373
ZonedDateTime.of(2000, 1, 1, 12, 0, 0, 0, ZoneOffset.UTC),
6474
READER.readValue(q("2000-01-01T12:00Z")));
6575
}
6676

77+
// [modules-java#281]
78+
@Test
79+
public void testDeserFromStringNoZoneIdNormalization() throws Exception
80+
{
81+
// 11-Nov-2023, tatu: Not sure this is great test but... does show diff
82+
// behavior with and without `JavaTimeFeature.NORMALIZE_DESERIALIZED_ZONE_ID`
83+
assertEquals("The value is not correct.",
84+
ZonedDateTime.of(2000, 1, 1, 12, 0, 0, 0, TimeZone.getTimeZone("UTC").toZoneId()),
85+
READER_NON_NORMALIZED_ZONEID.readValue(q("2000-01-01T12:00Z")));
86+
}
87+
6788
@Test
6889
public void testDeserializationAsInt01() throws Exception
6990
{

release-notes/VERSION-2.x

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,9 @@ Modules:
1313
#272: (datetime) `JsonFormat.Feature.WRITE_DATE_TIMESTAMPS_AS_NANOSECONDS`
1414
not respected when deserialising `Instant`s
1515
(fix contributed by Raman B)
16+
#281: (datetime) Add `JavaTimeFeature.NORMALIZE_DESERIALIZED_ZONE_ID` to allow
17+
disabling ZoneId normalization on deserialization
18+
(requested by @indyana)
1619

1720
2.15.3 (12-Oct-2023)
1821
2.15.2 (30-May-2023)

0 commit comments

Comments
 (0)