Skip to content

Commit

Permalink
Merge branch '2.16'
Browse files Browse the repository at this point in the history
  • Loading branch information
cowtowncoder committed Nov 12, 2023
2 parents 99efd87 + 734973b commit d4afe86
Show file tree
Hide file tree
Showing 4 changed files with 81 additions and 14 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
import java.time.*;

import tools.jackson.core.Version;
import tools.jackson.core.util.JacksonFeatureSet;
import tools.jackson.databind.*;
import tools.jackson.databind.deser.ValueInstantiator;
import tools.jackson.databind.deser.ValueInstantiators;
Expand Down Expand Up @@ -85,6 +86,9 @@ public final class JavaTimeModule
{
private static final long serialVersionUID = 1L;

private JacksonFeatureSet<JavaTimeFeature> _features
= JacksonFeatureSet.fromDefaults(JavaTimeFeature.values());

@Override
public String getModuleName() {
return getClass().getName();
Expand All @@ -97,13 +101,26 @@ public Version version() {

public JavaTimeModule() { }

public JavaTimeModule enable(JavaTimeFeature f) {
_features = _features.with(f);
return this;
}

public JavaTimeModule disable(JavaTimeFeature f) {
_features = _features.without(f);
return this;
}

@Override
public void setupModule(SetupContext context) {
context.addDeserializers(new SimpleDeserializers()
// // Instant variants:
.addDeserializer(Instant.class, InstantDeserializer.INSTANT)
.addDeserializer(OffsetDateTime.class, InstantDeserializer.OFFSET_DATE_TIME)
.addDeserializer(ZonedDateTime.class, InstantDeserializer.ZONED_DATE_TIME)
.addDeserializer(Instant.class,
InstantDeserializer.INSTANT.withFeatures(_features))
.addDeserializer(OffsetDateTime.class,
InstantDeserializer.OFFSET_DATE_TIME.withFeatures(_features))
.addDeserializer(ZonedDateTime.class,
InstantDeserializer.ZONED_DATE_TIME.withFeatures(_features))

// // Other deserializers
.addDeserializer(Duration.class, DurationDeserializer.INSTANCE)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,11 +17,7 @@
package tools.jackson.datatype.jsr310.deser;

import java.math.BigDecimal;
import java.time.DateTimeException;
import java.time.Instant;
import java.time.OffsetDateTime;
import java.time.ZoneId;
import java.time.ZonedDateTime;
import java.time.*;
import java.time.format.DateTimeFormatter;
import java.time.temporal.Temporal;
import java.time.temporal.TemporalAccessor;
Expand All @@ -38,22 +34,24 @@
import tools.jackson.core.JsonToken;
import tools.jackson.core.JsonTokenId;
import tools.jackson.core.io.NumberInput;

import tools.jackson.core.util.JacksonFeatureSet;
import tools.jackson.databind.BeanProperty;
import tools.jackson.databind.DeserializationContext;
import tools.jackson.databind.DeserializationFeature;
import tools.jackson.datatype.jsr310.JavaTimeFeature;
import tools.jackson.datatype.jsr310.util.DecimalUtils;

/**
* Deserializer for Java 8 temporal {@link Instant}s, {@link OffsetDateTime},
* and {@link ZonedDateTime}s.
*
* @author Nick Williams
* @since 2.2
*/
public class InstantDeserializer<T extends Temporal>
extends JSR310DateTimeDeserializerBase<T>
{
private final static boolean DEFAULT_NORMALIZE_ZONE_ID = JavaTimeFeature.NORMALIZE_DESERIALIZED_ZONE_ID.enabledByDefault();

/**
* Constants used to check if ISO 8601 time string is colonless. See [jackson-modules-java8#131]
*/
Expand All @@ -66,7 +64,7 @@ public class InstantDeserializer<T extends Temporal>
a -> Instant.ofEpochSecond(a.integer, a.fraction),
null,
true, // yes, replace zero offset with Z
true // default: yes, normalize ZoneId
DEFAULT_NORMALIZE_ZONE_ID
);

public static final InstantDeserializer<OffsetDateTime> OFFSET_DATE_TIME = new InstantDeserializer<>(
Expand All @@ -76,7 +74,7 @@ public class InstantDeserializer<T extends Temporal>
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 // default: yes, normalize ZoneId
DEFAULT_NORMALIZE_ZONE_ID
);

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

protected final Function<FromIntegerArguments, T> fromMilliseconds;
Expand Down Expand Up @@ -208,6 +206,26 @@ protected InstantDeserializer(InstantDeserializer<T> base,
_normalizeZoneId = base._normalizeZoneId;
}

/**
* @since 2.16
*/
@SuppressWarnings("unchecked")
protected InstantDeserializer(InstantDeserializer<T> base,
JacksonFeatureSet<JavaTimeFeature> features)
{
super((Class<T>) base.handledType(), base._formatter);
parsedToValue = base.parsedToValue;
fromMilliseconds = base.fromMilliseconds;
fromNanoseconds = base.fromNanoseconds;
adjust = base.adjust;
replaceZeroOffsetAsZ = base.replaceZeroOffsetAsZ;
_adjustToContextTZOverride = base._adjustToContextTZOverride;
_readTimestampsAsNanosOverride = base._readTimestampsAsNanosOverride;

_normalizeZoneId = features.isEnabled(JavaTimeFeature.NORMALIZE_DESERIALIZED_ZONE_ID);

}

@Override
protected InstantDeserializer<T> withDateFormat(DateTimeFormatter dtf) {
if (dtf == _formatter) {
Expand All @@ -221,6 +239,14 @@ protected InstantDeserializer<T> withLeniency(Boolean leniency) {
return new InstantDeserializer<>(this, _formatter, leniency);
}

// @since 2.16
public InstantDeserializer<T> withFeatures(JacksonFeatureSet<JavaTimeFeature> features) {
if (_normalizeZoneId == features.isEnabled(JavaTimeFeature.NORMALIZE_DESERIALIZED_ZONE_ID)) {
return this;
}
return new InstantDeserializer<>(this, features);
}

@SuppressWarnings("unchecked")
@Override // @since 2.12.1
protected JSR310DateTimeDeserializerBase<?> _withFormatOverrides(DeserializationContext ctxt,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
import java.time.ZonedDateTime;
import java.time.format.DateTimeFormatter;
import java.util.Map;
import java.util.TimeZone;

import com.fasterxml.jackson.annotation.JsonFormat;
import com.fasterxml.jackson.annotation.JsonFormat.Feature;
Expand All @@ -16,6 +17,9 @@
import tools.jackson.databind.ObjectMapper;
import tools.jackson.databind.ObjectReader;
import tools.jackson.databind.exc.MismatchedInputException;
import tools.jackson.databind.json.JsonMapper;
import tools.jackson.datatype.jsr310.JavaTimeFeature;
import tools.jackson.datatype.jsr310.JavaTimeModule;
import tools.jackson.datatype.jsr310.ModuleTestBase;

import org.junit.Test;
Expand All @@ -27,6 +31,12 @@
public class ZonedDateTimeDeserTest extends ModuleTestBase
{
private final ObjectReader READER = newMapper().readerFor(ZonedDateTime.class);

private final ObjectReader READER_NON_NORMALIZED_ZONEID = JsonMapper.builder()
.addModule(new JavaTimeModule().disable(JavaTimeFeature.NORMALIZE_DESERIALIZED_ZONE_ID))
.build()
.readerFor(ZonedDateTime.class);

private final TypeReference<Map<String, ZonedDateTime>> MAP_TYPE_REF = new TypeReference<Map<String, ZonedDateTime>>() { };

static class WrapperWithFeatures {
Expand Down Expand Up @@ -55,13 +65,24 @@ public WrapperWithReadTimestampsAsNanosEnabled() { }
}

@Test
public void testDeserializationAsString01() throws Exception
public void testDeserFromString() throws Exception
{
assertEquals("The value is not correct.",
ZonedDateTime.of(2000, 1, 1, 12, 0, 0, 0, ZoneOffset.UTC),
READER.readValue(q("2000-01-01T12:00Z")));
}

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

@Test
public void testDeserializationAsInt01() throws Exception
{
Expand Down
3 changes: 3 additions & 0 deletions release-notes/VERSION-2.x
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,9 @@ Modules:
#272: (datetime) `JsonFormat.Feature.WRITE_DATE_TIMESTAMPS_AS_NANOSECONDS`
not respected when deserialising `Instant`s
(fix contributed by Raman B)
#281: (datetime) Add `JavaTimeFeature.NORMALIZE_DESERIALIZED_ZONE_ID` to allow
disabling ZoneId normalization on deserialization
(requested by @indyana)

2.15.3 (12-Oct-2023)
2.15.2 (30-May-2023)
Expand Down

0 comments on commit d4afe86

Please sign in to comment.