From e03a06f145be8786bdd64d36c5b35b7bcb65cc8f Mon Sep 17 00:00:00 2001 From: Tatu Saloranta Date: Tue, 14 Jul 2020 20:58:32 -0700 Subject: [PATCH] Partial fix for #117 --- release-notes/VERSION-2.x | 1 + .../joda/deser/DateTimeDeserializer.java | 19 ++++++++++++++++--- .../joda/deser/InstantDeserializer.java | 2 +- .../joda/deser/IntervalDeserializer.java | 7 +++---- .../joda/deser/JodaDateDeserializerBase.java | 9 +++++++++ .../joda/deser/LocalTimeDeserializer.java | 6 ++++-- .../joda/deser/MonthDayDeserializer.java | 2 +- .../joda/deser/YearMonthDeserializer.java | 7 +++---- 8 files changed, 38 insertions(+), 15 deletions(-) diff --git a/release-notes/VERSION-2.x b/release-notes/VERSION-2.x index bd3c6b40..5da39710 100644 --- a/release-notes/VERSION-2.x +++ b/release-notes/VERSION-2.x @@ -8,6 +8,7 @@ Project: jackson-datatype-joda #116: Improve schema support for DateTimeZone type (contributed by Joost v-d-W) +#117: Timestamp deserialization not working for CSV, Properties or XML 2.11.1 (25-Jun-2020) diff --git a/src/main/java/com/fasterxml/jackson/datatype/joda/deser/DateTimeDeserializer.java b/src/main/java/com/fasterxml/jackson/datatype/joda/deser/DateTimeDeserializer.java index 36999222..c84ba3b4 100644 --- a/src/main/java/com/fasterxml/jackson/datatype/joda/deser/DateTimeDeserializer.java +++ b/src/main/java/com/fasterxml/jackson/datatype/joda/deser/DateTimeDeserializer.java @@ -9,7 +9,8 @@ import com.fasterxml.jackson.core.JsonParser; import com.fasterxml.jackson.core.JsonTokenId; - +import com.fasterxml.jackson.core.StreamReadCapability; +import com.fasterxml.jackson.core.io.NumberInput; import com.fasterxml.jackson.databind.DeserializationContext; import com.fasterxml.jackson.databind.JsonDeserializer; import com.fasterxml.jackson.datatype.joda.cfg.FormatConfig; @@ -48,8 +49,7 @@ public ReadableInstant deserialize(JsonParser p, DeserializationContext ctxt) DateTimeZone tz; switch (p.currentTokenId()) { case JsonTokenId.ID_NUMBER_INT: - tz = _format.isTimezoneExplicit() ? _format.getTimeZone() : DateTimeZone.forTimeZone(ctxt.getTimeZone()); - return new DateTime(p.getLongValue(), tz); + return _fromTimestamp(ctxt, p.getLongValue()); case JsonTokenId.ID_STRING: String str = p.getText().trim(); if (str.length() == 0) { @@ -92,10 +92,23 @@ public ReadableInstant deserialize(JsonParser p, DeserializationContext ctxt) } return result; } + // 14-Jul-2020: [datatype-joda#117] Should allow use of "Timestamp as String" for + // some textual formats + if (ctxt.isEnabled(StreamReadCapability.UNTYPED_SCALARS) + && _isValidTimestampString(str)) { + return _fromTimestamp(ctxt, NumberInput.parseLong(str)); + } + // Not sure if it should use timezone or not... // 15-Sep-2015, tatu: impl of 'createParser()' SHOULD handle all timezone/locale setup return _format.createParser(ctxt).parseDateTime(str); } return _handleNotNumberOrString(p, ctxt); } + + protected DateTime _fromTimestamp(DeserializationContext ctxt, long ts) { + DateTimeZone tz = _format.isTimezoneExplicit() ? _format.getTimeZone() + : DateTimeZone.forTimeZone(ctxt.getTimeZone()); + return new DateTime(ts, tz); + } } diff --git a/src/main/java/com/fasterxml/jackson/datatype/joda/deser/InstantDeserializer.java b/src/main/java/com/fasterxml/jackson/datatype/joda/deser/InstantDeserializer.java index 9e9f2b9a..884a9262 100644 --- a/src/main/java/com/fasterxml/jackson/datatype/joda/deser/InstantDeserializer.java +++ b/src/main/java/com/fasterxml/jackson/datatype/joda/deser/InstantDeserializer.java @@ -42,7 +42,7 @@ public Instant deserialize(JsonParser p, DeserializationContext ctxt) throws IOE case JsonTokenId.ID_STRING: String str = p.getText().trim(); if (str.length() == 0) { - return null; + return getNullValue(ctxt); } // 11-Sep-2018, tatu: `DateTimeDeserializer` allows timezone inclusion in brackets; // should that be checked here too? diff --git a/src/main/java/com/fasterxml/jackson/datatype/joda/deser/IntervalDeserializer.java b/src/main/java/com/fasterxml/jackson/datatype/joda/deser/IntervalDeserializer.java index c57550c9..2e4bb98e 100644 --- a/src/main/java/com/fasterxml/jackson/datatype/joda/deser/IntervalDeserializer.java +++ b/src/main/java/com/fasterxml/jackson/datatype/joda/deser/IntervalDeserializer.java @@ -36,14 +36,13 @@ public Interval deserialize(JsonParser p, DeserializationContext ctxt) { if (!p.hasToken(JsonToken.VALUE_STRING)) { return (Interval) ctxt.handleUnexpectedToken(handledType(), - p.getCurrentToken(), p, "expected JSON String"); + p.currentToken(), p, "expected JSON String"); } String v = p.getText().trim(); - /* 17-Nov-2014, tatu: Actually let's start with slash, instead of hyphen, because - * that is the separator for standard functionality... - */ + // 17-Nov-2014, tatu: Actually let's start with slash, instead of hyphen, because + // that is the separator for standard functionality... int index = v.indexOf('/', 1); boolean hasSlash = (index > 0); if (!hasSlash) { diff --git a/src/main/java/com/fasterxml/jackson/datatype/joda/deser/JodaDateDeserializerBase.java b/src/main/java/com/fasterxml/jackson/datatype/joda/deser/JodaDateDeserializerBase.java index e6003310..8541d449 100644 --- a/src/main/java/com/fasterxml/jackson/datatype/joda/deser/JodaDateDeserializerBase.java +++ b/src/main/java/com/fasterxml/jackson/datatype/joda/deser/JodaDateDeserializerBase.java @@ -1,6 +1,7 @@ package com.fasterxml.jackson.datatype.joda.deser; import com.fasterxml.jackson.annotation.JsonFormat; +import com.fasterxml.jackson.core.io.NumberInput; import com.fasterxml.jackson.databind.*; import com.fasterxml.jackson.databind.deser.ContextualDeserializer; import com.fasterxml.jackson.datatype.joda.cfg.JacksonJodaDateFormat; @@ -60,4 +61,12 @@ public JsonDeserializer createContextual(DeserializationContext ctxt, } return this; } + + // @since 2.12 + protected boolean _isValidTimestampString(String str) { + // 14-Jul-2020, tatu: Need to support "numbers as Strings" for data formats + // that only have String values for scalars (CSV, Properties, XML) + // NOTE: we do allow negative values, but has to fit in 64-bits: + return _isIntNumber(str) && NumberInput.inLongRange(str, (str.charAt(0) == '-')); + } } diff --git a/src/main/java/com/fasterxml/jackson/datatype/joda/deser/LocalTimeDeserializer.java b/src/main/java/com/fasterxml/jackson/datatype/joda/deser/LocalTimeDeserializer.java index e19409e3..9f0b6d47 100644 --- a/src/main/java/com/fasterxml/jackson/datatype/joda/deser/LocalTimeDeserializer.java +++ b/src/main/java/com/fasterxml/jackson/datatype/joda/deser/LocalTimeDeserializer.java @@ -38,8 +38,10 @@ public LocalTime deserialize(JsonParser p, DeserializationContext ctxt) return new LocalTime(p.getLongValue()); case JsonTokenId.ID_STRING: String str = p.getText().trim(); - return (str.length() == 0) ? null - : _format.createParser(ctxt).parseLocalTime(str); + if (str.length() == 0) { + return getNullValue(ctxt); + } + return _format.createParser(ctxt).parseLocalTime(str); default: } // [HH,MM,ss,ms?] diff --git a/src/main/java/com/fasterxml/jackson/datatype/joda/deser/MonthDayDeserializer.java b/src/main/java/com/fasterxml/jackson/datatype/joda/deser/MonthDayDeserializer.java index f5e3b37d..e360d57c 100644 --- a/src/main/java/com/fasterxml/jackson/datatype/joda/deser/MonthDayDeserializer.java +++ b/src/main/java/com/fasterxml/jackson/datatype/joda/deser/MonthDayDeserializer.java @@ -42,7 +42,7 @@ public MonthDay deserialize(final JsonParser p, final DeserializationContext ctx } return MonthDay.parse(str, _format.createParser(ctxt)); } - return (MonthDay) ctxt.handleUnexpectedToken(handledType(), p.getCurrentToken(), p, + return (MonthDay) ctxt.handleUnexpectedToken(handledType(), p.currentToken(), p, "expected JSON String"); } } diff --git a/src/main/java/com/fasterxml/jackson/datatype/joda/deser/YearMonthDeserializer.java b/src/main/java/com/fasterxml/jackson/datatype/joda/deser/YearMonthDeserializer.java index 51ed36f3..7c4fd463 100644 --- a/src/main/java/com/fasterxml/jackson/datatype/joda/deser/YearMonthDeserializer.java +++ b/src/main/java/com/fasterxml/jackson/datatype/joda/deser/YearMonthDeserializer.java @@ -35,15 +35,14 @@ public JodaDateDeserializerBase withFormat(JacksonJodaDateFormat format) { @Override public YearMonth deserialize(final JsonParser p, final DeserializationContext ctxt) throws IOException { - JsonToken t = p.getCurrentToken(); - if (t == JsonToken.VALUE_STRING) { + if (p.hasToken(JsonToken.VALUE_STRING)) { String str = p.getText().trim(); if (str.isEmpty()) { - return null; + return getNullValue(ctxt); } return YearMonth.parse(str, _format.createParser(ctxt)); } - return (YearMonth) ctxt.handleUnexpectedToken(handledType(), p.getCurrentToken(), p, + return (YearMonth) ctxt.handleUnexpectedToken(handledType(), p.currentToken(), p, "expected JSON String"); } }