Skip to content

Sync with databind#4656 changes #370

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
May 18, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -355,17 +355,21 @@ 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
return (T) 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);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -125,61 +125,65 @@ public LocalDateDeserializer withFeatures(JacksonFeatureSet<JavaTimeFeature> 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,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -148,70 +148,74 @@ public LocalDateTimeDeserializer withFeatures(JacksonFeatureSet<JavaTimeFeature>
}

@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);
}
}
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) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -103,69 +103,73 @@ 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);
}
}
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) {
Expand Down
Loading
Loading