Skip to content

Commit

Permalink
Initial part of #281: add scaffolding for configurable zoneid normali…
Browse files Browse the repository at this point in the history
…zation (#284)
  • Loading branch information
cowtowncoder committed Nov 12, 2023
1 parent 572cde0 commit 79d0379
Show file tree
Hide file tree
Showing 2 changed files with 32 additions and 7 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,14 @@
public enum JavaTimeFeature implements JacksonFeature
{
/**
* Placeholder
* Feature that determines whether {@link java.time.ZoneId} is normalized
* (via call to {@code java.time.ZoneId#normalized()}) when deserializing
* types like {@link java.time.ZonedDateTime}.
*<p>
* Default setting is enabled, for backwards-compatibility with
* Jackson 2.15.
*/
BOGUS(false);
NORMALIZE_DESERIALIZED_ZONE_ID(true);

/**
* Whether feature is enabled or disabled by default.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,8 @@ public class InstantDeserializer<T extends Temporal>
a -> Instant.ofEpochMilli(a.value),
a -> Instant.ofEpochSecond(a.integer, a.fraction),
null,
true // yes, replace zero offset with Z
true, // yes, replace zero offset with Z
true // default: yes, normalize ZoneId
);

public static final InstantDeserializer<OffsetDateTime> OFFSET_DATE_TIME = new InstantDeserializer<>(
Expand All @@ -76,7 +77,8 @@ public class InstantDeserializer<T extends Temporal>
a -> OffsetDateTime.ofInstant(Instant.ofEpochMilli(a.value), a.zoneId),
a -> OffsetDateTime.ofInstant(Instant.ofEpochSecond(a.integer, a.fraction), a.zoneId),
(d, z) -> (d.isEqual(OffsetDateTime.MIN) || d.isEqual(OffsetDateTime.MAX) ? d : d.withOffsetSameInstant(z.getRules().getOffset(d.toLocalDateTime()))),
true // yes, replace zero offset with Z
true, // yes, replace zero offset with Z
true // default: yes, normalize ZoneId
);

public static final InstantDeserializer<ZonedDateTime> ZONED_DATE_TIME = new InstantDeserializer<>(
Expand All @@ -85,7 +87,8 @@ public class InstantDeserializer<T extends Temporal>
a -> ZonedDateTime.ofInstant(Instant.ofEpochMilli(a.value), a.zoneId),
a -> ZonedDateTime.ofInstant(Instant.ofEpochSecond(a.integer, a.fraction), a.zoneId),
ZonedDateTime::withZoneSameInstant,
false // keep zero offset and Z separate since zones explicitly supported
false, // keep zero offset and Z separate since zones explicitly supported
true // default: yes, normalize ZoneId
);

protected final Function<FromIntegerArguments, T> fromMilliseconds;
Expand Down Expand Up @@ -119,13 +122,21 @@ public class InstantDeserializer<T extends Temporal>
*/
protected final Boolean _readTimestampsAsNanosOverride;

/**
* Flag set from
* {@link com.fasterxml.jackson.datatype.jsr310.JavaTimeFeature#NORMALIZE_DESERIALIZED_ZONE_ID} to
* determine whether {@link ZoneId} is to be normalized during deserialization.
*/
protected final boolean _normalizeZoneId;

protected InstantDeserializer(Class<T> supportedType,
DateTimeFormatter formatter,
Function<TemporalAccessor, T> parsedToValue,
Function<FromIntegerArguments, T> fromMilliseconds,
Function<FromDecimalArguments, T> fromNanoseconds,
BiFunction<T, ZoneId, T> adjust,
boolean replaceZeroOffsetAsZ)
boolean replaceZeroOffsetAsZ,
boolean normalizeZoneId)
{
super(supportedType, formatter);
this.parsedToValue = parsedToValue;
Expand All @@ -135,6 +146,7 @@ protected InstantDeserializer(Class<T> supportedType,
this.replaceZeroOffsetAsZ = replaceZeroOffsetAsZ;
this._adjustToContextTZOverride = null;
this._readTimestampsAsNanosOverride = null;
_normalizeZoneId = normalizeZoneId;
}

@SuppressWarnings("unchecked")
Expand All @@ -148,6 +160,7 @@ protected InstantDeserializer(InstantDeserializer<T> base, DateTimeFormatter f)
replaceZeroOffsetAsZ = (_formatter == DateTimeFormatter.ISO_INSTANT);
_adjustToContextTZOverride = base._adjustToContextTZOverride;
_readTimestampsAsNanosOverride = base._readTimestampsAsNanosOverride;
_normalizeZoneId = base._normalizeZoneId;
}

@SuppressWarnings("unchecked")
Expand All @@ -161,6 +174,7 @@ protected InstantDeserializer(InstantDeserializer<T> base, Boolean adjustToConte
replaceZeroOffsetAsZ = base.replaceZeroOffsetAsZ;
_adjustToContextTZOverride = adjustToContextTimezoneOverride;
_readTimestampsAsNanosOverride = base._readTimestampsAsNanosOverride;
_normalizeZoneId = base._normalizeZoneId;
}

@SuppressWarnings("unchecked")
Expand All @@ -174,6 +188,7 @@ protected InstantDeserializer(InstantDeserializer<T> base, DateTimeFormatter f,
replaceZeroOffsetAsZ = (_formatter == DateTimeFormatter.ISO_INSTANT);
_adjustToContextTZOverride = base._adjustToContextTZOverride;
_readTimestampsAsNanosOverride = base._readTimestampsAsNanosOverride;
_normalizeZoneId = base._normalizeZoneId;
}

/**
Expand All @@ -194,6 +209,7 @@ protected InstantDeserializer(InstantDeserializer<T> base,
replaceZeroOffsetAsZ = base.replaceZeroOffsetAsZ;
_adjustToContextTZOverride = adjustToContextTimezoneOverride;
_readTimestampsAsNanosOverride = readTimestampsAsNanosOverride;
_normalizeZoneId = base._normalizeZoneId;
}

@Override
Expand Down Expand Up @@ -364,7 +380,11 @@ private ZoneId getZone(DeserializationContext context)
// Instants are always in UTC, so don't waste compute cycles
// Normalizing the zone to prevent discrepancies.
// See https://github.com/FasterXML/jackson-modules-java8/pull/267 for details
return (_valueClass == Instant.class) ? null : context.getTimeZone().toZoneId().normalized();
if (_valueClass == Instant.class) {
return null;
}
ZoneId zoneId = context.getTimeZone().toZoneId();
return _normalizeZoneId ? zoneId.normalized() : zoneId;
}

private String replaceZeroOffsetAsZIfNecessary(String text)
Expand Down

0 comments on commit 79d0379

Please sign in to comment.