diff --git a/datetime/src/main/java/com/fasterxml/jackson/datatype/jsr310/deser/DurationDeserializer.java b/datetime/src/main/java/com/fasterxml/jackson/datatype/jsr310/deser/DurationDeserializer.java index 2a7945e8..79a1fc25 100644 --- a/datetime/src/main/java/com/fasterxml/jackson/datatype/jsr310/deser/DurationDeserializer.java +++ b/datetime/src/main/java/com/fasterxml/jackson/datatype/jsr310/deser/DurationDeserializer.java @@ -162,17 +162,20 @@ public Duration deserialize(JsonParser parser, DeserializationContext context) t return _fromTimestamp(context, parser.getLongValue()); case JsonTokenId.ID_STRING: return _fromString(parser, context, parser.getText()); - // 30-Sep-2020, tatu: New! "Scalar from Object" (mostly for XML) - case JsonTokenId.ID_START_OBJECT: - return _fromString(parser, context, - context.extractScalarFromObject(parser, this, handledType())); case JsonTokenId.ID_EMBEDDED_OBJECT: // 20-Apr-2016, tatu: Related to [databind#1208], can try supporting embedded // values quite easily return (Duration) parser.getEmbeddedObject(); - case JsonTokenId.ID_START_ARRAY: return _deserializeFromArray(parser, context); + // 30-Sep-2020, tatu: New! "Scalar from Object" (mostly for XML) + case JsonTokenId.ID_START_OBJECT: + // 17-May-2025, tatu: [databind#4656] need to check for `null` + String str = context.extractScalarFromObject(parser, this, handledType()); + if (str != null) { + return _fromString(parser, context, str); + } + // fall through } return _handleUnexpectedToken(context, parser, JsonToken.VALUE_STRING, JsonToken.VALUE_NUMBER_INT, JsonToken.VALUE_NUMBER_FLOAT); diff --git a/datetime/src/main/java/com/fasterxml/jackson/datatype/jsr310/deser/InstantDeserializer.java b/datetime/src/main/java/com/fasterxml/jackson/datatype/jsr310/deser/InstantDeserializer.java index 4f406931..0e1bf808 100644 --- a/datetime/src/main/java/com/fasterxml/jackson/datatype/jsr310/deser/InstantDeserializer.java +++ b/datetime/src/main/java/com/fasterxml/jackson/datatype/jsr310/deser/InstantDeserializer.java @@ -355,10 +355,6 @@ public T deserialize(JsonParser parser, DeserializationContext context) throws I return _fromLong(context, parser.getLongValue()); case JsonTokenId.ID_STRING: return _fromString(parser, context, parser.getText()); - // 30-Sep-2020, tatu: New! "Scalar from Object" (mostly for XML) - case JsonTokenId.ID_START_OBJECT: - return _fromString(parser, context, - context.extractScalarFromObject(parser, this, handledType())); case JsonTokenId.ID_EMBEDDED_OBJECT: // 20-Apr-2016, tatu: Related to [databind#1208], can try supporting embedded // values quite easily @@ -366,6 +362,14 @@ public T deserialize(JsonParser parser, DeserializationContext context) throws I case JsonTokenId.ID_START_ARRAY: return _deserializeFromArray(parser, context); + // 30-Sep-2020, tatu: New! "Scalar from Object" (mostly for XML) + case JsonTokenId.ID_START_OBJECT: + // 17-May-2025, tatu: [databind#4656] need to check for `null` + String str = context.extractScalarFromObject(parser, this, handledType()); + if (str != null) { + return _fromString(parser, context, str); + } + // fall through } return _handleUnexpectedToken(context, parser, JsonToken.VALUE_STRING, JsonToken.VALUE_NUMBER_INT, JsonToken.VALUE_NUMBER_FLOAT); diff --git a/datetime/src/main/java/com/fasterxml/jackson/datatype/jsr310/deser/JSR310StringParsableDeserializer.java b/datetime/src/main/java/com/fasterxml/jackson/datatype/jsr310/deser/JSR310StringParsableDeserializer.java index 5cb8e465..96596a34 100644 --- a/datetime/src/main/java/com/fasterxml/jackson/datatype/jsr310/deser/JSR310StringParsableDeserializer.java +++ b/datetime/src/main/java/com/fasterxml/jackson/datatype/jsr310/deser/JSR310StringParsableDeserializer.java @@ -122,15 +122,17 @@ public Object deserialize(JsonParser p, DeserializationContext ctxt) throws IOEx } // 30-Sep-2020, tatu: New! "Scalar from Object" (mostly for XML) if (p.isExpectedStartObjectToken()) { - return _fromString(p, ctxt, - ctxt.extractScalarFromObject(p, this, handledType())); - } - if (p.hasToken(JsonToken.VALUE_EMBEDDED_OBJECT)) { + // 17-May-2025, tatu: [databind#4656] need to check for `null` + String str = ctxt.extractScalarFromObject(p, this, handledType()); + if (str != null) { + return _fromString(p, ctxt, str); + } + // fall through + } else if (p.hasToken(JsonToken.VALUE_EMBEDDED_OBJECT)) { // 20-Apr-2016, tatu: Related to [databind#1208], can try supporting embedded // values quite easily return p.getEmbeddedObject(); - } - if (p.isExpectedStartArrayToken()) { + } else if (p.isExpectedStartArrayToken()) { return _deserializeFromArray(p, ctxt); } diff --git a/datetime/src/main/java/com/fasterxml/jackson/datatype/jsr310/deser/LocalDateDeserializer.java b/datetime/src/main/java/com/fasterxml/jackson/datatype/jsr310/deser/LocalDateDeserializer.java index 4a19d89b..5775a1d4 100644 --- a/datetime/src/main/java/com/fasterxml/jackson/datatype/jsr310/deser/LocalDateDeserializer.java +++ b/datetime/src/main/java/com/fasterxml/jackson/datatype/jsr310/deser/LocalDateDeserializer.java @@ -125,61 +125,65 @@ public LocalDateDeserializer withFeatures(JacksonFeatureSet fea } @Override - public LocalDate deserialize(JsonParser parser, DeserializationContext context) throws IOException + public LocalDate deserialize(JsonParser p, DeserializationContext ctxt) throws IOException { - if (parser.hasToken(JsonToken.VALUE_STRING)) { - return _fromString(parser, context, parser.getText()); + if (p.hasToken(JsonToken.VALUE_STRING)) { + return _fromString(p, ctxt, p.getText()); } // 30-Sep-2020, tatu: New! "Scalar from Object" (mostly for XML) - if (parser.isExpectedStartObjectToken()) { - return _fromString(parser, context, - context.extractScalarFromObject(parser, this, handledType())); + if (p.isExpectedStartObjectToken()) { + // 17-May-2025, tatu: [databind#4656] need to check for `null` + String str = ctxt.extractScalarFromObject(p, this, handledType()); + if (str != null) { + return _fromString(p, ctxt, str); + } + return _handleUnexpectedToken(ctxt, p, "Expected array or string"); } - if (parser.isExpectedStartArrayToken()) { - JsonToken t = parser.nextToken(); + if (p.isExpectedStartArrayToken()) { + JsonToken t = p.nextToken(); if (t == JsonToken.END_ARRAY) { return null; } - if (context.isEnabled(DeserializationFeature.UNWRAP_SINGLE_VALUE_ARRAYS) + if (ctxt.isEnabled(DeserializationFeature.UNWRAP_SINGLE_VALUE_ARRAYS) && (t == JsonToken.VALUE_STRING || t==JsonToken.VALUE_EMBEDDED_OBJECT)) { - final LocalDate parsed = deserialize(parser, context); - if (parser.nextToken() != JsonToken.END_ARRAY) { - handleMissingEndArrayForSingle(parser, context); + final LocalDate parsed = deserialize(p, ctxt); + if (p.nextToken() != JsonToken.END_ARRAY) { + handleMissingEndArrayForSingle(p, ctxt); } return parsed; } if (t == JsonToken.VALUE_NUMBER_INT) { - int year = parser.getIntValue(); - int month = parser.nextIntValue(-1); - int day = parser.nextIntValue(-1); + int year = p.getIntValue(); + int month = p.nextIntValue(-1); + int day = p.nextIntValue(-1); - if (parser.nextToken() != JsonToken.END_ARRAY) { - throw context.wrongTokenException(parser, handledType(), JsonToken.END_ARRAY, + if (p.nextToken() != JsonToken.END_ARRAY) { + throw ctxt.wrongTokenException(p, handledType(), JsonToken.END_ARRAY, "Expected array to end"); } return LocalDate.of(year, month, day); } - context.reportInputMismatch(handledType(), + ctxt.reportInputMismatch(handledType(), "Unexpected token (%s) within Array, expected VALUE_NUMBER_INT", t); } - if (parser.hasToken(JsonToken.VALUE_EMBEDDED_OBJECT)) { - return (LocalDate) parser.getEmbeddedObject(); + if (p.hasToken(JsonToken.VALUE_EMBEDDED_OBJECT)) { + return (LocalDate) p.getEmbeddedObject(); } // 06-Jan-2018, tatu: Is this actually safe? Do users expect such coercion? - if (parser.hasToken(JsonToken.VALUE_NUMBER_INT)) { - CoercionAction act = context.findCoercionAction(logicalType(), _valueClass, + if (p.hasToken(JsonToken.VALUE_NUMBER_INT)) { + CoercionAction act = ctxt.findCoercionAction(logicalType(), _valueClass, CoercionInputShape.Integer); - _checkCoercionFail(context, act, handledType(), parser.getLongValue(), - "Integer value (" + parser.getLongValue() + ")"); + _checkCoercionFail(ctxt, act, handledType(), p.getLongValue(), + "Integer value (" + p.getLongValue() + ")"); // issue 58 - also check for NUMBER_INT, which needs to be specified when serializing. if (_shape == JsonFormat.Shape.NUMBER_INT || isLenient()) { - return LocalDate.ofEpochDay(parser.getLongValue()); + return LocalDate.ofEpochDay(p.getLongValue()); } - return _failForNotLenient(parser, context, JsonToken.VALUE_STRING); + return _failForNotLenient(p, ctxt, JsonToken.VALUE_STRING); } - return _handleUnexpectedToken(context, parser, "Expected array or string."); + return _handleUnexpectedToken(ctxt, p, "Expected array or string"); } protected LocalDate _fromString(JsonParser p, DeserializationContext ctxt, diff --git a/datetime/src/main/java/com/fasterxml/jackson/datatype/jsr310/deser/LocalDateTimeDeserializer.java b/datetime/src/main/java/com/fasterxml/jackson/datatype/jsr310/deser/LocalDateTimeDeserializer.java index 7c88f8cb..c76fdb0d 100644 --- a/datetime/src/main/java/com/fasterxml/jackson/datatype/jsr310/deser/LocalDateTimeDeserializer.java +++ b/datetime/src/main/java/com/fasterxml/jackson/datatype/jsr310/deser/LocalDateTimeDeserializer.java @@ -148,52 +148,56 @@ public LocalDateTimeDeserializer withFeatures(JacksonFeatureSet } @Override - public LocalDateTime deserialize(JsonParser parser, DeserializationContext context) throws IOException + public LocalDateTime deserialize(JsonParser p, DeserializationContext ctxt) throws IOException { - if (parser.hasTokenId(JsonTokenId.ID_STRING)) { - return _fromString(parser, context, parser.getText()); + if (p.hasTokenId(JsonTokenId.ID_STRING)) { + return _fromString(p, ctxt, p.getText()); } // 30-Sep-2020, tatu: New! "Scalar from Object" (mostly for XML) - if (parser.isExpectedStartObjectToken()) { - return _fromString(parser, context, - context.extractScalarFromObject(parser, this, handledType())); + if (p.isExpectedStartObjectToken()) { + // 17-May-2025, tatu: [databind#4656] need to check for `null` + String str = ctxt.extractScalarFromObject(p, this, handledType()); + if (str != null) { + return _fromString(p, ctxt, str); + } + return _handleUnexpectedToken(ctxt, p, "Expected array or string"); } - if (parser.isExpectedStartArrayToken()) { - JsonToken t = parser.nextToken(); + if (p.isExpectedStartArrayToken()) { + JsonToken t = p.nextToken(); if (t == JsonToken.END_ARRAY) { return null; } if ((t == JsonToken.VALUE_STRING || t == JsonToken.VALUE_EMBEDDED_OBJECT) - && context.isEnabled(DeserializationFeature.UNWRAP_SINGLE_VALUE_ARRAYS)) { - final LocalDateTime parsed = deserialize(parser, context); - if (parser.nextToken() != JsonToken.END_ARRAY) { - handleMissingEndArrayForSingle(parser, context); + && ctxt.isEnabled(DeserializationFeature.UNWRAP_SINGLE_VALUE_ARRAYS)) { + final LocalDateTime parsed = deserialize(p, ctxt); + if (p.nextToken() != JsonToken.END_ARRAY) { + handleMissingEndArrayForSingle(p, ctxt); } return parsed; } if (t == JsonToken.VALUE_NUMBER_INT) { LocalDateTime result; - int year = parser.getIntValue(); - int month = parser.nextIntValue(-1); - int day = parser.nextIntValue(-1); - int hour = parser.nextIntValue(-1); - int minute = parser.nextIntValue(-1); + int year = p.getIntValue(); + int month = p.nextIntValue(-1); + int day = p.nextIntValue(-1); + int hour = p.nextIntValue(-1); + int minute = p.nextIntValue(-1); - t = parser.nextToken(); + t = p.nextToken(); if (t == JsonToken.END_ARRAY) { result = LocalDateTime.of(year, month, day, hour, minute); } else { - int second = parser.getIntValue(); - t = parser.nextToken(); + int second = p.getIntValue(); + t = p.nextToken(); if (t == JsonToken.END_ARRAY) { result = LocalDateTime.of(year, month, day, hour, minute, second); } else { - int partialSecond = parser.getIntValue(); - if (partialSecond < 1_000 && !shouldReadTimestampsAsNanoseconds(context)) + int partialSecond = p.getIntValue(); + if (partialSecond < 1_000 && !shouldReadTimestampsAsNanoseconds(ctxt)) partialSecond *= 1_000_000; // value is milliseconds, convert it to nanoseconds - if (parser.nextToken() != JsonToken.END_ARRAY) { - throw context.wrongTokenException(parser, handledType(), JsonToken.END_ARRAY, + if (p.nextToken() != JsonToken.END_ARRAY) { + throw ctxt.wrongTokenException(p, handledType(), JsonToken.END_ARRAY, "Expected array to end"); } result = LocalDateTime.of(year, month, day, hour, minute, second, partialSecond); @@ -201,17 +205,17 @@ public LocalDateTime deserialize(JsonParser parser, DeserializationContext conte } return result; } - context.reportInputMismatch(handledType(), + ctxt.reportInputMismatch(handledType(), "Unexpected token (%s) within Array, expected VALUE_NUMBER_INT", t); } - if (parser.hasToken(JsonToken.VALUE_EMBEDDED_OBJECT)) { - return (LocalDateTime) parser.getEmbeddedObject(); + if (p.hasToken(JsonToken.VALUE_EMBEDDED_OBJECT)) { + return (LocalDateTime) p.getEmbeddedObject(); } - if (parser.hasToken(JsonToken.VALUE_NUMBER_INT)) { - _throwNoNumericTimestampNeedTimeZone(parser, context); + if (p.hasToken(JsonToken.VALUE_NUMBER_INT)) { + _throwNoNumericTimestampNeedTimeZone(p, ctxt); } - return _handleUnexpectedToken(context, parser, "Expected array or string."); + return _handleUnexpectedToken(ctxt, p, "Expected array or string"); } protected boolean shouldReadTimestampsAsNanoseconds(DeserializationContext context) { diff --git a/datetime/src/main/java/com/fasterxml/jackson/datatype/jsr310/deser/LocalTimeDeserializer.java b/datetime/src/main/java/com/fasterxml/jackson/datatype/jsr310/deser/LocalTimeDeserializer.java index da860cf3..f023be9a 100644 --- a/datetime/src/main/java/com/fasterxml/jackson/datatype/jsr310/deser/LocalTimeDeserializer.java +++ b/datetime/src/main/java/com/fasterxml/jackson/datatype/jsr310/deser/LocalTimeDeserializer.java @@ -103,51 +103,55 @@ protected JSR310DateTimeDeserializerBase _withFormatOverrides(Deserialization } @Override - public LocalTime deserialize(JsonParser parser, DeserializationContext context) throws IOException + public LocalTime deserialize(JsonParser p, DeserializationContext ctxt) throws IOException { - if (parser.hasToken(JsonToken.VALUE_STRING)) { - return _fromString(parser, context, parser.getText()); + if (p.hasToken(JsonToken.VALUE_STRING)) { + return _fromString(p, ctxt, p.getText()); } // 30-Sep-2020, tatu: New! "Scalar from Object" (mostly for XML) - if (parser.isExpectedStartObjectToken()) { - return _fromString(parser, context, - context.extractScalarFromObject(parser, this, handledType())); + if (p.isExpectedStartObjectToken()) { + // 17-May-2025, tatu: [databind#4656] need to check for `null` + String str = ctxt.extractScalarFromObject(p, this, handledType()); + if (str != null) { + return _fromString(p, ctxt, str); + } + return _handleUnexpectedToken(ctxt, p, "Expected array or string"); } - if (parser.isExpectedStartArrayToken()) { - JsonToken t = parser.nextToken(); + if (p.isExpectedStartArrayToken()) { + JsonToken t = p.nextToken(); if (t == JsonToken.END_ARRAY) { return null; } - if (context.isEnabled(DeserializationFeature.UNWRAP_SINGLE_VALUE_ARRAYS) + if (ctxt.isEnabled(DeserializationFeature.UNWRAP_SINGLE_VALUE_ARRAYS) && (t == JsonToken.VALUE_STRING || t==JsonToken.VALUE_EMBEDDED_OBJECT)) { - final LocalTime parsed = deserialize(parser, context); - if (parser.nextToken() != JsonToken.END_ARRAY) { - handleMissingEndArrayForSingle(parser, context); + final LocalTime parsed = deserialize(p, ctxt); + if (p.nextToken() != JsonToken.END_ARRAY) { + handleMissingEndArrayForSingle(p, ctxt); } return parsed; } if (t == JsonToken.VALUE_NUMBER_INT) { - int hour = parser.getIntValue(); + int hour = p.getIntValue(); - parser.nextToken(); - int minute = parser.getIntValue(); + p.nextToken(); + int minute = p.getIntValue(); LocalTime result; - t = parser.nextToken(); + t = p.nextToken(); if (t == JsonToken.END_ARRAY) { result = LocalTime.of(hour, minute); } else { - int second = parser.getIntValue(); - t = parser.nextToken(); + int second = p.getIntValue(); + t = p.nextToken(); if (t == JsonToken.END_ARRAY) { result = LocalTime.of(hour, minute, second); } else { - int partialSecond = parser.getIntValue(); - if(partialSecond < 1_000 && !shouldReadTimestampsAsNanoseconds(context)) + int partialSecond = p.getIntValue(); + if(partialSecond < 1_000 && !shouldReadTimestampsAsNanoseconds(ctxt)) partialSecond *= 1_000_000; // value is milliseconds, convert it to nanoseconds - t = parser.nextToken(); + t = p.nextToken(); if (t != JsonToken.END_ARRAY) { - throw context.wrongTokenException(parser, handledType(), JsonToken.END_ARRAY, + throw ctxt.wrongTokenException(p, handledType(), JsonToken.END_ARRAY, "Expected array to end"); } result = LocalTime.of(hour, minute, second, partialSecond); @@ -155,17 +159,17 @@ public LocalTime deserialize(JsonParser parser, DeserializationContext context) } return result; } - context.reportInputMismatch(handledType(), + ctxt.reportInputMismatch(handledType(), "Unexpected token (%s) within Array, expected VALUE_NUMBER_INT", t); } - if (parser.hasToken(JsonToken.VALUE_EMBEDDED_OBJECT)) { - return (LocalTime) parser.getEmbeddedObject(); + if (p.hasToken(JsonToken.VALUE_EMBEDDED_OBJECT)) { + return (LocalTime) p.getEmbeddedObject(); } - if (parser.hasToken(JsonToken.VALUE_NUMBER_INT)) { - _throwNoNumericTimestampNeedTimeZone(parser, context); + if (p.hasToken(JsonToken.VALUE_NUMBER_INT)) { + _throwNoNumericTimestampNeedTimeZone(p, ctxt); } - return _handleUnexpectedToken(context, parser, "Expected array or string."); + return _handleUnexpectedToken(ctxt, p, "Expected array or string"); } protected boolean shouldReadTimestampsAsNanoseconds(DeserializationContext context) { diff --git a/datetime/src/main/java/com/fasterxml/jackson/datatype/jsr310/deser/MonthDayDeserializer.java b/datetime/src/main/java/com/fasterxml/jackson/datatype/jsr310/deser/MonthDayDeserializer.java index 449cf718..88d71697 100644 --- a/datetime/src/main/java/com/fasterxml/jackson/datatype/jsr310/deser/MonthDayDeserializer.java +++ b/datetime/src/main/java/com/fasterxml/jackson/datatype/jsr310/deser/MonthDayDeserializer.java @@ -62,50 +62,52 @@ protected MonthDayDeserializer withDateFormat(DateTimeFormatter dtf) { } @Override - public MonthDay deserialize(JsonParser parser, DeserializationContext context) throws IOException + public MonthDay deserialize(JsonParser p, DeserializationContext ctxt) throws IOException { - if (parser.hasToken(JsonToken.VALUE_STRING)) { - return _fromString(parser, context, parser.getText()); + if (p.hasToken(JsonToken.VALUE_STRING)) { + return _fromString(p, ctxt, p.getText()); } // 30-Sep-2020, tatu: New! "Scalar from Object" (mostly for XML) - if (parser.isExpectedStartObjectToken()) { - return _fromString(parser, context, - context.extractScalarFromObject(parser, this, handledType())); - } - if (parser.isExpectedStartArrayToken()) { - JsonToken t = parser.nextToken(); + if (p.isExpectedStartObjectToken()) { + // 17-May-2025, tatu: [databind#4656] need to check for `null` + String str = ctxt.extractScalarFromObject(p, this, handledType()); + if (str != null) { + return _fromString(p, ctxt, str); + } + // fall through + } else if (p.isExpectedStartArrayToken()) { + JsonToken t = p.nextToken(); if (t == JsonToken.END_ARRAY) { return null; } if ((t == JsonToken.VALUE_STRING || t == JsonToken.VALUE_EMBEDDED_OBJECT) - && context.isEnabled(DeserializationFeature.UNWRAP_SINGLE_VALUE_ARRAYS)) { - final MonthDay parsed = deserialize(parser, context); - if (parser.nextToken() != JsonToken.END_ARRAY) { - handleMissingEndArrayForSingle(parser, context); + && ctxt.isEnabled(DeserializationFeature.UNWRAP_SINGLE_VALUE_ARRAYS)) { + final MonthDay parsed = deserialize(p, ctxt); + if (p.nextToken() != JsonToken.END_ARRAY) { + handleMissingEndArrayForSingle(p, ctxt); } return parsed; } if (t != JsonToken.VALUE_NUMBER_INT) { - _reportWrongToken(context, JsonToken.VALUE_NUMBER_INT, "month"); + _reportWrongToken(ctxt, JsonToken.VALUE_NUMBER_INT, "month"); } - int month = parser.getIntValue(); - int day = parser.nextIntValue(-1); + int month = p.getIntValue(); + int day = p.nextIntValue(-1); if (day == -1) { - if (!parser.hasToken(JsonToken.VALUE_NUMBER_INT)) { - _reportWrongToken(context, JsonToken.VALUE_NUMBER_INT, "day"); + if (!p.hasToken(JsonToken.VALUE_NUMBER_INT)) { + _reportWrongToken(ctxt, JsonToken.VALUE_NUMBER_INT, "day"); } - day = parser.getIntValue(); + day = p.getIntValue(); } - if (parser.nextToken() != JsonToken.END_ARRAY) { - throw context.wrongTokenException(parser, handledType(), JsonToken.END_ARRAY, + if (p.nextToken() != JsonToken.END_ARRAY) { + throw ctxt.wrongTokenException(p, handledType(), JsonToken.END_ARRAY, "Expected array to end"); } return MonthDay.of(month, day); + } else if (p.hasToken(JsonToken.VALUE_EMBEDDED_OBJECT)) { + return (MonthDay) p.getEmbeddedObject(); } - if (parser.hasToken(JsonToken.VALUE_EMBEDDED_OBJECT)) { - return (MonthDay) parser.getEmbeddedObject(); - } - return _handleUnexpectedToken(context, parser, + return _handleUnexpectedToken(ctxt, p, JsonToken.VALUE_STRING, JsonToken.START_ARRAY); } diff --git a/datetime/src/main/java/com/fasterxml/jackson/datatype/jsr310/deser/OffsetTimeDeserializer.java b/datetime/src/main/java/com/fasterxml/jackson/datatype/jsr310/deser/OffsetTimeDeserializer.java index 8331af7f..0a23ac39 100644 --- a/datetime/src/main/java/com/fasterxml/jackson/datatype/jsr310/deser/OffsetTimeDeserializer.java +++ b/datetime/src/main/java/com/fasterxml/jackson/datatype/jsr310/deser/OffsetTimeDeserializer.java @@ -99,75 +99,79 @@ protected JSR310DateTimeDeserializerBase _withFormatOverrides(Deserialization } @Override - public OffsetTime deserialize(JsonParser parser, DeserializationContext context) throws IOException + public OffsetTime deserialize(JsonParser p, DeserializationContext ctxt) throws IOException { - if (parser.hasToken(JsonToken.VALUE_STRING)) { - return _fromString(parser, context, parser.getText()); + if (p.hasToken(JsonToken.VALUE_STRING)) { + return _fromString(p, ctxt, p.getText()); } // 30-Sep-2020, tatu: New! "Scalar from Object" (mostly for XML) - if (parser.isExpectedStartObjectToken()) { - return _fromString(parser, context, - context.extractScalarFromObject(parser, this, handledType())); + if (p.isExpectedStartObjectToken()) { + // 17-May-2025, tatu: [databind#4656] need to check for `null` + String str = ctxt.extractScalarFromObject(p, this, handledType()); + if (str != null) { + return _fromString(p, ctxt, str); + } + // fall through } - if (!parser.isExpectedStartArrayToken()) { - if (parser.hasToken(JsonToken.VALUE_EMBEDDED_OBJECT)) { - return (OffsetTime) parser.getEmbeddedObject(); + if (!p.isExpectedStartArrayToken()) { + if (p.hasToken(JsonToken.VALUE_EMBEDDED_OBJECT)) { + return (OffsetTime) p.getEmbeddedObject(); } - if (parser.hasToken(JsonToken.VALUE_NUMBER_INT)) { - _throwNoNumericTimestampNeedTimeZone(parser, context); + if (p.hasToken(JsonToken.VALUE_NUMBER_INT)) { + _throwNoNumericTimestampNeedTimeZone(p, ctxt); } - throw context.wrongTokenException(parser, handledType(), JsonToken.START_ARRAY, + throw ctxt.wrongTokenException(p, handledType(), JsonToken.START_ARRAY, "Expected array or string."); } - JsonToken t = parser.nextToken(); + JsonToken t = p.nextToken(); if (t != JsonToken.VALUE_NUMBER_INT) { if (t == JsonToken.END_ARRAY) { return null; } if ((t == JsonToken.VALUE_STRING || t == JsonToken.VALUE_EMBEDDED_OBJECT) - && context.isEnabled(DeserializationFeature.UNWRAP_SINGLE_VALUE_ARRAYS)) { - final OffsetTime parsed = deserialize(parser, context); - if (parser.nextToken() != JsonToken.END_ARRAY) { - handleMissingEndArrayForSingle(parser, context); + && ctxt.isEnabled(DeserializationFeature.UNWRAP_SINGLE_VALUE_ARRAYS)) { + final OffsetTime parsed = deserialize(p, ctxt); + if (p.nextToken() != JsonToken.END_ARRAY) { + handleMissingEndArrayForSingle(p, ctxt); } return parsed; } - context.reportInputMismatch(handledType(), + ctxt.reportInputMismatch(handledType(), "Unexpected token (%s) within Array, expected VALUE_NUMBER_INT", t); } - int hour = parser.getIntValue(); - int minute = parser.nextIntValue(-1); + int hour = p.getIntValue(); + int minute = p.nextIntValue(-1); if (minute == -1) { - t = parser.getCurrentToken(); + t = p.getCurrentToken(); if (t == JsonToken.END_ARRAY) { return null; } if (t != JsonToken.VALUE_NUMBER_INT) { - _reportWrongToken(context, JsonToken.VALUE_NUMBER_INT, "minutes"); + _reportWrongToken(ctxt, JsonToken.VALUE_NUMBER_INT, "minutes"); } - minute = parser.getIntValue(); + minute = p.getIntValue(); } int partialSecond = 0; int second = 0; - if (parser.nextToken() == JsonToken.VALUE_NUMBER_INT) { - second = parser.getIntValue(); - if (parser.nextToken() == JsonToken.VALUE_NUMBER_INT) { - partialSecond = parser.getIntValue(); - if (partialSecond < 1_000 && !shouldReadTimestampsAsNanoseconds(context)) { + if (p.nextToken() == JsonToken.VALUE_NUMBER_INT) { + second = p.getIntValue(); + if (p.nextToken() == JsonToken.VALUE_NUMBER_INT) { + partialSecond = p.getIntValue(); + if (partialSecond < 1_000 && !shouldReadTimestampsAsNanoseconds(ctxt)) { partialSecond *= 1_000_000; // value is milliseconds, convert it to nanoseconds } - parser.nextToken(); + p.nextToken(); } } - if (parser.getCurrentToken() == JsonToken.VALUE_STRING) { - OffsetTime result = OffsetTime.of(hour, minute, second, partialSecond, ZoneOffset.of(parser.getText())); - if (parser.nextToken() != JsonToken.END_ARRAY) { - _reportWrongToken(context, JsonToken.END_ARRAY, "timezone"); + if (p.getCurrentToken() == JsonToken.VALUE_STRING) { + OffsetTime result = OffsetTime.of(hour, minute, second, partialSecond, ZoneOffset.of(p.getText())); + if (p.nextToken() != JsonToken.END_ARRAY) { + _reportWrongToken(ctxt, JsonToken.END_ARRAY, "timezone"); } return result; } - throw context.wrongTokenException(parser, handledType(), JsonToken.VALUE_STRING, + throw ctxt.wrongTokenException(p, handledType(), JsonToken.VALUE_STRING, "Expected string for TimeZone after numeric values"); } diff --git a/datetime/src/main/java/com/fasterxml/jackson/datatype/jsr310/deser/OneBasedMonthDeserializer.java b/datetime/src/main/java/com/fasterxml/jackson/datatype/jsr310/deser/OneBasedMonthDeserializer.java index f1153459..d6b71680 100644 --- a/datetime/src/main/java/com/fasterxml/jackson/datatype/jsr310/deser/OneBasedMonthDeserializer.java +++ b/datetime/src/main/java/com/fasterxml/jackson/datatype/jsr310/deser/OneBasedMonthDeserializer.java @@ -4,7 +4,7 @@ import java.time.Month; import com.fasterxml.jackson.core.JsonParser; -import com.fasterxml.jackson.core.JsonToken; + import com.fasterxml.jackson.databind.DeserializationContext; import com.fasterxml.jackson.databind.JsonDeserializer; import com.fasterxml.jackson.databind.deser.std.DelegatingDeserializer; @@ -21,21 +21,21 @@ public OneBasedMonthDeserializer(JsonDeserializer defaultDeserializer) { } @Override - public Object deserialize(JsonParser parser, DeserializationContext context) throws IOException { - JsonToken token = parser.currentToken(); - switch (token) { - case VALUE_NUMBER_INT: - return _decodeMonth(parser.getIntValue(), parser); - case VALUE_STRING: - String monthSpec = parser.getText(); - int oneBasedMonthNumber = _decodeNumber(monthSpec); - if (oneBasedMonthNumber >= 0) { - return _decodeMonth(oneBasedMonthNumber, parser); - } - // Otherwise fall through to default handling - break; + public Object deserialize(JsonParser p, DeserializationContext ctxt) throws IOException { + switch (p.currentToken()) { + case VALUE_NUMBER_INT: + return _decodeMonth(p.getIntValue(), p); + case VALUE_STRING: + String monthSpec = p.getText(); + int oneBasedMonthNumber = _decodeNumber(monthSpec); + if (oneBasedMonthNumber >= 0) { + return _decodeMonth(oneBasedMonthNumber, p); + } + // Otherwise fall through to default handling + break; + default: } - return getDelegatee().deserialize(parser, context); + return getDelegatee().deserialize(p, ctxt); } /** diff --git a/datetime/src/main/java/com/fasterxml/jackson/datatype/jsr310/deser/YearDeserializer.java b/datetime/src/main/java/com/fasterxml/jackson/datatype/jsr310/deser/YearDeserializer.java index d34db205..7e6c3603 100644 --- a/datetime/src/main/java/com/fasterxml/jackson/datatype/jsr310/deser/YearDeserializer.java +++ b/datetime/src/main/java/com/fasterxml/jackson/datatype/jsr310/deser/YearDeserializer.java @@ -79,27 +79,28 @@ protected YearDeserializer withLeniency(Boolean leniency) { } @Override - public Year deserialize(JsonParser parser, DeserializationContext context) throws IOException + public Year deserialize(JsonParser p, DeserializationContext ctxt) throws IOException { - JsonToken t = parser.currentToken(); + JsonToken t = p.currentToken(); if (t == JsonToken.VALUE_STRING) { - return _fromString(parser, context, parser.getText()); + return _fromString(p, ctxt, p.getText()); } // 30-Sep-2020, tatu: New! "Scalar from Object" (mostly for XML) if (t == JsonToken.START_OBJECT) { - return _fromString(parser, context, - context.extractScalarFromObject(parser, this, handledType())); - } - if (t == JsonToken.VALUE_NUMBER_INT) { - return _fromNumber(context, parser.getIntValue()); - } - if (t == JsonToken.VALUE_EMBEDDED_OBJECT) { - return (Year) parser.getEmbeddedObject(); - } - if (parser.hasToken(JsonToken.START_ARRAY)){ - return _deserializeFromArray(parser, context); + // 17-May-2025, tatu: [databind#4656] need to check for `null` + String str = ctxt.extractScalarFromObject(p, this, handledType()); + if (str != null) { + return _fromString(p, ctxt, str); + } + // fall through + } else if (t == JsonToken.VALUE_NUMBER_INT) { + return _fromNumber(ctxt, p.getIntValue()); + } else if (t == JsonToken.VALUE_EMBEDDED_OBJECT) { + return (Year) p.getEmbeddedObject(); + } else if (p.isExpectedStartArrayToken()){ + return _deserializeFromArray(p, ctxt); } - return _handleUnexpectedToken(context, parser, JsonToken.VALUE_STRING, JsonToken.VALUE_NUMBER_INT); + return _handleUnexpectedToken(ctxt, p, JsonToken.VALUE_STRING, JsonToken.VALUE_NUMBER_INT); } protected Year _fromString(JsonParser p, DeserializationContext ctxt, diff --git a/datetime/src/main/java/com/fasterxml/jackson/datatype/jsr310/deser/YearMonthDeserializer.java b/datetime/src/main/java/com/fasterxml/jackson/datatype/jsr310/deser/YearMonthDeserializer.java index 58709ffa..4114343e 100644 --- a/datetime/src/main/java/com/fasterxml/jackson/datatype/jsr310/deser/YearMonthDeserializer.java +++ b/datetime/src/main/java/com/fasterxml/jackson/datatype/jsr310/deser/YearMonthDeserializer.java @@ -81,50 +81,52 @@ protected YearMonthDeserializer withLeniency(Boolean leniency) { } @Override - public YearMonth deserialize(JsonParser parser, DeserializationContext context) throws IOException + public YearMonth deserialize(JsonParser p, DeserializationContext ctxt) throws IOException { - if (parser.hasToken(JsonToken.VALUE_STRING)) { - return _fromString(parser, context, parser.getText()); + if (p.hasToken(JsonToken.VALUE_STRING)) { + return _fromString(p, ctxt, p.getText()); } // 30-Sep-2020, tatu: New! "Scalar from Object" (mostly for XML) - if (parser.isExpectedStartObjectToken()) { - return _fromString(parser, context, - context.extractScalarFromObject(parser, this, handledType())); - } - if (parser.isExpectedStartArrayToken()) { - JsonToken t = parser.nextToken(); + if (p.isExpectedStartObjectToken()) { + // 17-May-2025, tatu: [databind#4656] need to check for `null` + String str = ctxt.extractScalarFromObject(p, this, handledType()); + if (str != null) { + return _fromString(p, ctxt, str); + } + // fall through + } else if (p.isExpectedStartArrayToken()) { + JsonToken t = p.nextToken(); if (t == JsonToken.END_ARRAY) { return null; } if ((t == JsonToken.VALUE_STRING || t == JsonToken.VALUE_EMBEDDED_OBJECT) - && context.isEnabled(DeserializationFeature.UNWRAP_SINGLE_VALUE_ARRAYS)) { - final YearMonth parsed = deserialize(parser, context); - if (parser.nextToken() != JsonToken.END_ARRAY) { - handleMissingEndArrayForSingle(parser, context); + && ctxt.isEnabled(DeserializationFeature.UNWRAP_SINGLE_VALUE_ARRAYS)) { + final YearMonth parsed = deserialize(p, ctxt); + if (p.nextToken() != JsonToken.END_ARRAY) { + handleMissingEndArrayForSingle(p, ctxt); } return parsed; } if (t != JsonToken.VALUE_NUMBER_INT) { - _reportWrongToken(context, JsonToken.VALUE_NUMBER_INT, "years"); + _reportWrongToken(ctxt, JsonToken.VALUE_NUMBER_INT, "years"); } - int year = parser.getIntValue(); - int month = parser.nextIntValue(-1); + int year = p.getIntValue(); + int month = p.nextIntValue(-1); if (month == -1) { - if (!parser.hasToken(JsonToken.VALUE_NUMBER_INT)) { - _reportWrongToken(context, JsonToken.VALUE_NUMBER_INT, "months"); + if (!p.hasToken(JsonToken.VALUE_NUMBER_INT)) { + _reportWrongToken(ctxt, JsonToken.VALUE_NUMBER_INT, "months"); } - month = parser.getIntValue(); + month = p.getIntValue(); } - if (parser.nextToken() != JsonToken.END_ARRAY) { - throw context.wrongTokenException(parser, handledType(), JsonToken.END_ARRAY, + if (p.nextToken() != JsonToken.END_ARRAY) { + throw ctxt.wrongTokenException(p, handledType(), JsonToken.END_ARRAY, "Expected array to end"); } return YearMonth.of(year, month); + } else if (p.hasToken(JsonToken.VALUE_EMBEDDED_OBJECT)) { + return (YearMonth) p.getEmbeddedObject(); } - if (parser.hasToken(JsonToken.VALUE_EMBEDDED_OBJECT)) { - return (YearMonth) parser.getEmbeddedObject(); - } - return _handleUnexpectedToken(context, parser, + return _handleUnexpectedToken(ctxt, p, JsonToken.VALUE_STRING, JsonToken.START_ARRAY); }