diff --git a/src/main/java/com/fasterxml/jackson/datatype/joda/deser/DateMidnightDeserializer.java b/src/main/java/com/fasterxml/jackson/datatype/joda/deser/DateMidnightDeserializer.java index 7935cd4b..9820a253 100644 --- a/src/main/java/com/fasterxml/jackson/datatype/joda/deser/DateMidnightDeserializer.java +++ b/src/main/java/com/fasterxml/jackson/datatype/joda/deser/DateMidnightDeserializer.java @@ -9,6 +9,8 @@ import com.fasterxml.jackson.core.JsonParser; import com.fasterxml.jackson.core.JsonToken; 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.datatype.joda.cfg.FormatConfig; import com.fasterxml.jackson.datatype.joda.cfg.JacksonJodaDateFormat; @@ -45,7 +47,6 @@ public JodaDateDeserializerBase withFormat(JacksonJodaDateFormat format) { public DateMidnight deserialize(JsonParser p, DeserializationContext ctxt) throws IOException { - // We'll accept either long (timestamp) or array: if (p.isExpectedStartArrayToken()) { p.nextToken(); // VALUE_NUMBER_INT @@ -55,7 +56,7 @@ public DateMidnight deserialize(JsonParser p, DeserializationContext ctxt) p.nextToken(); // VALUE_NUMBER_INT int day = p.getIntValue(); if (p.nextToken() != JsonToken.END_ARRAY) { - throw ctxt.wrongTokenException(p, JsonToken.END_ARRAY, + throw ctxt.wrongTokenException(p, handledType(), JsonToken.END_ARRAY, "after DateMidnight ints"); } DateTimeZone tz = _format.isTimezoneExplicit() ? _format.getTimeZone() : DateTimeZone.forTimeZone(ctxt.getTimeZone()); @@ -70,6 +71,12 @@ public DateMidnight deserialize(JsonParser p, DeserializationContext ctxt) if (str.length() == 0) { // [JACKSON-360] return null; } + // 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 new DateMidnight(NumberInput.parseLong(str)); + } LocalDate local = _format.createParser(ctxt).parseLocalDate(str); if (local == null) { return null; @@ -80,4 +87,9 @@ public DateMidnight deserialize(JsonParser p, DeserializationContext ctxt) throw ctxt.wrongTokenException(p, handledType(), JsonToken.START_ARRAY, "expected JSON Array, Number or String"); } -} \ No newline at end of file + + protected DateMidnight _fromTimestamp(DeserializationContext ctxt, long ts) { + return new DateMidnight(ts); + } + +} 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 884a9262..3a7b1e9e 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 @@ -5,7 +5,7 @@ import org.joda.time.Instant; import com.fasterxml.jackson.core.*; - +import com.fasterxml.jackson.core.io.NumberInput; import com.fasterxml.jackson.databind.*; import com.fasterxml.jackson.datatype.joda.cfg.FormatConfig; import com.fasterxml.jackson.datatype.joda.cfg.JacksonJodaDateFormat; @@ -44,6 +44,12 @@ public Instant deserialize(JsonParser p, DeserializationContext ctxt) throws IOE if (str.length() == 0) { return getNullValue(ctxt); } + // 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 new Instant(NumberInput.parseLong(str)); + } // 11-Sep-2018, tatu: `DateTimeDeserializer` allows timezone inclusion in brackets; // should that be checked here too? return Instant.parse(str, _format.createParser(ctxt)); diff --git a/src/main/java/com/fasterxml/jackson/datatype/joda/deser/LocalDateDeserializer.java b/src/main/java/com/fasterxml/jackson/datatype/joda/deser/LocalDateDeserializer.java index d1294672..ef3f30ed 100644 --- a/src/main/java/com/fasterxml/jackson/datatype/joda/deser/LocalDateDeserializer.java +++ b/src/main/java/com/fasterxml/jackson/datatype/joda/deser/LocalDateDeserializer.java @@ -8,7 +8,8 @@ import com.fasterxml.jackson.core.JsonParser; import com.fasterxml.jackson.core.JsonToken; 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.datatype.joda.cfg.FormatConfig; import com.fasterxml.jackson.datatype.joda.cfg.JacksonJodaDateFormat; @@ -37,13 +38,18 @@ public LocalDate deserialize(JsonParser p, DeserializationContext ctxt) throws I switch (p.currentTokenId()) { case JsonTokenId.ID_STRING: String str = p.getText().trim(); - return (str.length() == 0) ? null - : _format.createParser(ctxt).parseLocalDate(str); - case JsonTokenId.ID_NUMBER_INT: - { - DateTimeZone tz = _format.isTimezoneExplicit() ? _format.getTimeZone() : DateTimeZone.forTimeZone(ctxt.getTimeZone()); - return new LocalDate(p.getLongValue(), tz); + if (str.length() == 0) { + return getNullValue(ctxt); + } + // 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)); } + return _format.createParser(ctxt).parseLocalDate(str); + case JsonTokenId.ID_NUMBER_INT: + return _fromTimestamp(ctxt, p.getLongValue()); case JsonTokenId.ID_START_ARRAY: // [yyyy,mm,dd] or ["yyyy","mm","dd"] int year = p.nextIntValue(-1); // fast speculative case @@ -63,7 +69,13 @@ public LocalDate deserialize(JsonParser p, DeserializationContext ctxt) throws I } return new LocalDate(year, month, day); } - return (LocalDate) ctxt.handleUnexpectedToken(handledType(), p.getCurrentToken(), p, + return (LocalDate) ctxt.handleUnexpectedToken(handledType(), p.currentToken(), p, "expected String, Number or JSON Array"); } + + protected LocalDate _fromTimestamp(DeserializationContext ctxt, long ts) { + DateTimeZone tz = _format.isTimezoneExplicit() ? _format.getTimeZone() + : DateTimeZone.forTimeZone(ctxt.getTimeZone()); + return new LocalDate(ts, tz); + } } diff --git a/src/main/java/com/fasterxml/jackson/datatype/joda/deser/LocalDateTimeDeserializer.java b/src/main/java/com/fasterxml/jackson/datatype/joda/deser/LocalDateTimeDeserializer.java index 7a497c45..84226e70 100644 --- a/src/main/java/com/fasterxml/jackson/datatype/joda/deser/LocalDateTimeDeserializer.java +++ b/src/main/java/com/fasterxml/jackson/datatype/joda/deser/LocalDateTimeDeserializer.java @@ -6,7 +6,7 @@ import org.joda.time.LocalDateTime; import com.fasterxml.jackson.core.*; - +import com.fasterxml.jackson.core.io.NumberInput; import com.fasterxml.jackson.databind.DeserializationContext; import com.fasterxml.jackson.datatype.joda.cfg.FormatConfig; import com.fasterxml.jackson.datatype.joda.cfg.JacksonJodaDateFormat; @@ -37,14 +37,19 @@ public LocalDateTime deserialize(JsonParser p, DeserializationContext ctxt) case JsonTokenId.ID_STRING: { String str = p.getText().trim(); - return (str.length() == 0) ? null - : _format.createParser(ctxt).parseLocalDateTime(str); + if (str.length() == 0) { + return getNullValue(ctxt); + } + // 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)); + } + return _format.createParser(ctxt).parseLocalDateTime(str); } case JsonTokenId.ID_NUMBER_INT: - { - DateTimeZone tz = _format.isTimezoneExplicit() ? _format.getTimeZone() : DateTimeZone.forTimeZone(ctxt.getTimeZone()); - return new LocalDateTime(p.getLongValue(), tz); - } + return _fromTimestamp(ctxt, p.getLongValue()); case JsonTokenId.ID_START_ARRAY: // [yyyy,mm,dd,hh,MM,ss,ms] JsonToken t = p.nextToken(); @@ -82,7 +87,13 @@ public LocalDateTime deserialize(JsonParser p, DeserializationContext ctxt) throw ctxt.wrongTokenException(p, handledType(), JsonToken.END_ARRAY, "after LocalDateTime ints"); default: } - return (LocalDateTime) ctxt.handleUnexpectedToken(handledType(), p.getCurrentToken(), p, + return (LocalDateTime) ctxt.handleUnexpectedToken(handledType(), p.currentToken(), p, "expected String, Number or JSON Array"); } + + protected LocalDateTime _fromTimestamp(DeserializationContext ctxt, long ts) { + DateTimeZone tz = _format.isTimezoneExplicit() ? _format.getTimeZone() + : DateTimeZone.forTimeZone(ctxt.getTimeZone()); + return new LocalDateTime(ts, tz); + } } 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 9f0b6d47..d0191295 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 @@ -7,6 +7,8 @@ import com.fasterxml.jackson.core.JsonParser; import com.fasterxml.jackson.core.JsonToken; 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.datatype.joda.cfg.FormatConfig; import com.fasterxml.jackson.datatype.joda.cfg.JacksonJodaDateFormat; @@ -41,6 +43,12 @@ public LocalTime deserialize(JsonParser p, DeserializationContext ctxt) if (str.length() == 0) { return getNullValue(ctxt); } + // 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 new LocalTime(NumberInput.parseLong(str)); + } return _format.createParser(ctxt).parseLocalTime(str); default: }