Skip to content

Commit 63c7b8e

Browse files
authored
Sync with databind#4656 changes (#370)
1 parent 72066ea commit 63c7b8e

11 files changed

+244
-214
lines changed

datetime/src/main/java/com/fasterxml/jackson/datatype/jsr310/deser/DurationDeserializer.java

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -162,17 +162,20 @@ public Duration deserialize(JsonParser parser, DeserializationContext context) t
162162
return _fromTimestamp(context, parser.getLongValue());
163163
case JsonTokenId.ID_STRING:
164164
return _fromString(parser, context, parser.getText());
165-
// 30-Sep-2020, tatu: New! "Scalar from Object" (mostly for XML)
166-
case JsonTokenId.ID_START_OBJECT:
167-
return _fromString(parser, context,
168-
context.extractScalarFromObject(parser, this, handledType()));
169165
case JsonTokenId.ID_EMBEDDED_OBJECT:
170166
// 20-Apr-2016, tatu: Related to [databind#1208], can try supporting embedded
171167
// values quite easily
172168
return (Duration) parser.getEmbeddedObject();
173-
174169
case JsonTokenId.ID_START_ARRAY:
175170
return _deserializeFromArray(parser, context);
171+
// 30-Sep-2020, tatu: New! "Scalar from Object" (mostly for XML)
172+
case JsonTokenId.ID_START_OBJECT:
173+
// 17-May-2025, tatu: [databind#4656] need to check for `null`
174+
String str = context.extractScalarFromObject(parser, this, handledType());
175+
if (str != null) {
176+
return _fromString(parser, context, str);
177+
}
178+
// fall through
176179
}
177180
return _handleUnexpectedToken(context, parser, JsonToken.VALUE_STRING,
178181
JsonToken.VALUE_NUMBER_INT, JsonToken.VALUE_NUMBER_FLOAT);

datetime/src/main/java/com/fasterxml/jackson/datatype/jsr310/deser/InstantDeserializer.java

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -355,17 +355,21 @@ public T deserialize(JsonParser parser, DeserializationContext context) throws I
355355
return _fromLong(context, parser.getLongValue());
356356
case JsonTokenId.ID_STRING:
357357
return _fromString(parser, context, parser.getText());
358-
// 30-Sep-2020, tatu: New! "Scalar from Object" (mostly for XML)
359-
case JsonTokenId.ID_START_OBJECT:
360-
return _fromString(parser, context,
361-
context.extractScalarFromObject(parser, this, handledType()));
362358
case JsonTokenId.ID_EMBEDDED_OBJECT:
363359
// 20-Apr-2016, tatu: Related to [databind#1208], can try supporting embedded
364360
// values quite easily
365361
return (T) parser.getEmbeddedObject();
366362

367363
case JsonTokenId.ID_START_ARRAY:
368364
return _deserializeFromArray(parser, context);
365+
// 30-Sep-2020, tatu: New! "Scalar from Object" (mostly for XML)
366+
case JsonTokenId.ID_START_OBJECT:
367+
// 17-May-2025, tatu: [databind#4656] need to check for `null`
368+
String str = context.extractScalarFromObject(parser, this, handledType());
369+
if (str != null) {
370+
return _fromString(parser, context, str);
371+
}
372+
// fall through
369373
}
370374
return _handleUnexpectedToken(context, parser, JsonToken.VALUE_STRING,
371375
JsonToken.VALUE_NUMBER_INT, JsonToken.VALUE_NUMBER_FLOAT);

datetime/src/main/java/com/fasterxml/jackson/datatype/jsr310/deser/JSR310StringParsableDeserializer.java

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -122,15 +122,17 @@ public Object deserialize(JsonParser p, DeserializationContext ctxt) throws IOEx
122122
}
123123
// 30-Sep-2020, tatu: New! "Scalar from Object" (mostly for XML)
124124
if (p.isExpectedStartObjectToken()) {
125-
return _fromString(p, ctxt,
126-
ctxt.extractScalarFromObject(p, this, handledType()));
127-
}
128-
if (p.hasToken(JsonToken.VALUE_EMBEDDED_OBJECT)) {
125+
// 17-May-2025, tatu: [databind#4656] need to check for `null`
126+
String str = ctxt.extractScalarFromObject(p, this, handledType());
127+
if (str != null) {
128+
return _fromString(p, ctxt, str);
129+
}
130+
// fall through
131+
} else if (p.hasToken(JsonToken.VALUE_EMBEDDED_OBJECT)) {
129132
// 20-Apr-2016, tatu: Related to [databind#1208], can try supporting embedded
130133
// values quite easily
131134
return p.getEmbeddedObject();
132-
}
133-
if (p.isExpectedStartArrayToken()) {
135+
} else if (p.isExpectedStartArrayToken()) {
134136
return _deserializeFromArray(p, ctxt);
135137
}
136138

datetime/src/main/java/com/fasterxml/jackson/datatype/jsr310/deser/LocalDateDeserializer.java

Lines changed: 31 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -125,61 +125,65 @@ public LocalDateDeserializer withFeatures(JacksonFeatureSet<JavaTimeFeature> fea
125125
}
126126

127127
@Override
128-
public LocalDate deserialize(JsonParser parser, DeserializationContext context) throws IOException
128+
public LocalDate deserialize(JsonParser p, DeserializationContext ctxt) throws IOException
129129
{
130-
if (parser.hasToken(JsonToken.VALUE_STRING)) {
131-
return _fromString(parser, context, parser.getText());
130+
if (p.hasToken(JsonToken.VALUE_STRING)) {
131+
return _fromString(p, ctxt, p.getText());
132132
}
133133
// 30-Sep-2020, tatu: New! "Scalar from Object" (mostly for XML)
134-
if (parser.isExpectedStartObjectToken()) {
135-
return _fromString(parser, context,
136-
context.extractScalarFromObject(parser, this, handledType()));
134+
if (p.isExpectedStartObjectToken()) {
135+
// 17-May-2025, tatu: [databind#4656] need to check for `null`
136+
String str = ctxt.extractScalarFromObject(p, this, handledType());
137+
if (str != null) {
138+
return _fromString(p, ctxt, str);
139+
}
140+
return _handleUnexpectedToken(ctxt, p, "Expected array or string");
137141
}
138-
if (parser.isExpectedStartArrayToken()) {
139-
JsonToken t = parser.nextToken();
142+
if (p.isExpectedStartArrayToken()) {
143+
JsonToken t = p.nextToken();
140144
if (t == JsonToken.END_ARRAY) {
141145
return null;
142146
}
143-
if (context.isEnabled(DeserializationFeature.UNWRAP_SINGLE_VALUE_ARRAYS)
147+
if (ctxt.isEnabled(DeserializationFeature.UNWRAP_SINGLE_VALUE_ARRAYS)
144148
&& (t == JsonToken.VALUE_STRING || t==JsonToken.VALUE_EMBEDDED_OBJECT)) {
145-
final LocalDate parsed = deserialize(parser, context);
146-
if (parser.nextToken() != JsonToken.END_ARRAY) {
147-
handleMissingEndArrayForSingle(parser, context);
149+
final LocalDate parsed = deserialize(p, ctxt);
150+
if (p.nextToken() != JsonToken.END_ARRAY) {
151+
handleMissingEndArrayForSingle(p, ctxt);
148152
}
149153
return parsed;
150154
}
151155
if (t == JsonToken.VALUE_NUMBER_INT) {
152-
int year = parser.getIntValue();
153-
int month = parser.nextIntValue(-1);
154-
int day = parser.nextIntValue(-1);
156+
int year = p.getIntValue();
157+
int month = p.nextIntValue(-1);
158+
int day = p.nextIntValue(-1);
155159

156-
if (parser.nextToken() != JsonToken.END_ARRAY) {
157-
throw context.wrongTokenException(parser, handledType(), JsonToken.END_ARRAY,
160+
if (p.nextToken() != JsonToken.END_ARRAY) {
161+
throw ctxt.wrongTokenException(p, handledType(), JsonToken.END_ARRAY,
158162
"Expected array to end");
159163
}
160164
return LocalDate.of(year, month, day);
161165
}
162-
context.reportInputMismatch(handledType(),
166+
ctxt.reportInputMismatch(handledType(),
163167
"Unexpected token (%s) within Array, expected VALUE_NUMBER_INT",
164168
t);
165169
}
166-
if (parser.hasToken(JsonToken.VALUE_EMBEDDED_OBJECT)) {
167-
return (LocalDate) parser.getEmbeddedObject();
170+
if (p.hasToken(JsonToken.VALUE_EMBEDDED_OBJECT)) {
171+
return (LocalDate) p.getEmbeddedObject();
168172
}
169173
// 06-Jan-2018, tatu: Is this actually safe? Do users expect such coercion?
170-
if (parser.hasToken(JsonToken.VALUE_NUMBER_INT)) {
171-
CoercionAction act = context.findCoercionAction(logicalType(), _valueClass,
174+
if (p.hasToken(JsonToken.VALUE_NUMBER_INT)) {
175+
CoercionAction act = ctxt.findCoercionAction(logicalType(), _valueClass,
172176
CoercionInputShape.Integer);
173-
_checkCoercionFail(context, act, handledType(), parser.getLongValue(),
174-
"Integer value (" + parser.getLongValue() + ")");
177+
_checkCoercionFail(ctxt, act, handledType(), p.getLongValue(),
178+
"Integer value (" + p.getLongValue() + ")");
175179

176180
// issue 58 - also check for NUMBER_INT, which needs to be specified when serializing.
177181
if (_shape == JsonFormat.Shape.NUMBER_INT || isLenient()) {
178-
return LocalDate.ofEpochDay(parser.getLongValue());
182+
return LocalDate.ofEpochDay(p.getLongValue());
179183
}
180-
return _failForNotLenient(parser, context, JsonToken.VALUE_STRING);
184+
return _failForNotLenient(p, ctxt, JsonToken.VALUE_STRING);
181185
}
182-
return _handleUnexpectedToken(context, parser, "Expected array or string.");
186+
return _handleUnexpectedToken(ctxt, p, "Expected array or string");
183187
}
184188

185189
protected LocalDate _fromString(JsonParser p, DeserializationContext ctxt,

datetime/src/main/java/com/fasterxml/jackson/datatype/jsr310/deser/LocalDateTimeDeserializer.java

Lines changed: 34 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -148,70 +148,74 @@ public LocalDateTimeDeserializer withFeatures(JacksonFeatureSet<JavaTimeFeature>
148148
}
149149

150150
@Override
151-
public LocalDateTime deserialize(JsonParser parser, DeserializationContext context) throws IOException
151+
public LocalDateTime deserialize(JsonParser p, DeserializationContext ctxt) throws IOException
152152
{
153-
if (parser.hasTokenId(JsonTokenId.ID_STRING)) {
154-
return _fromString(parser, context, parser.getText());
153+
if (p.hasTokenId(JsonTokenId.ID_STRING)) {
154+
return _fromString(p, ctxt, p.getText());
155155
}
156156
// 30-Sep-2020, tatu: New! "Scalar from Object" (mostly for XML)
157-
if (parser.isExpectedStartObjectToken()) {
158-
return _fromString(parser, context,
159-
context.extractScalarFromObject(parser, this, handledType()));
157+
if (p.isExpectedStartObjectToken()) {
158+
// 17-May-2025, tatu: [databind#4656] need to check for `null`
159+
String str = ctxt.extractScalarFromObject(p, this, handledType());
160+
if (str != null) {
161+
return _fromString(p, ctxt, str);
162+
}
163+
return _handleUnexpectedToken(ctxt, p, "Expected array or string");
160164
}
161-
if (parser.isExpectedStartArrayToken()) {
162-
JsonToken t = parser.nextToken();
165+
if (p.isExpectedStartArrayToken()) {
166+
JsonToken t = p.nextToken();
163167
if (t == JsonToken.END_ARRAY) {
164168
return null;
165169
}
166170
if ((t == JsonToken.VALUE_STRING || t == JsonToken.VALUE_EMBEDDED_OBJECT)
167-
&& context.isEnabled(DeserializationFeature.UNWRAP_SINGLE_VALUE_ARRAYS)) {
168-
final LocalDateTime parsed = deserialize(parser, context);
169-
if (parser.nextToken() != JsonToken.END_ARRAY) {
170-
handleMissingEndArrayForSingle(parser, context);
171+
&& ctxt.isEnabled(DeserializationFeature.UNWRAP_SINGLE_VALUE_ARRAYS)) {
172+
final LocalDateTime parsed = deserialize(p, ctxt);
173+
if (p.nextToken() != JsonToken.END_ARRAY) {
174+
handleMissingEndArrayForSingle(p, ctxt);
171175
}
172176
return parsed;
173177
}
174178
if (t == JsonToken.VALUE_NUMBER_INT) {
175179
LocalDateTime result;
176180

177-
int year = parser.getIntValue();
178-
int month = parser.nextIntValue(-1);
179-
int day = parser.nextIntValue(-1);
180-
int hour = parser.nextIntValue(-1);
181-
int minute = parser.nextIntValue(-1);
181+
int year = p.getIntValue();
182+
int month = p.nextIntValue(-1);
183+
int day = p.nextIntValue(-1);
184+
int hour = p.nextIntValue(-1);
185+
int minute = p.nextIntValue(-1);
182186

183-
t = parser.nextToken();
187+
t = p.nextToken();
184188
if (t == JsonToken.END_ARRAY) {
185189
result = LocalDateTime.of(year, month, day, hour, minute);
186190
} else {
187-
int second = parser.getIntValue();
188-
t = parser.nextToken();
191+
int second = p.getIntValue();
192+
t = p.nextToken();
189193
if (t == JsonToken.END_ARRAY) {
190194
result = LocalDateTime.of(year, month, day, hour, minute, second);
191195
} else {
192-
int partialSecond = parser.getIntValue();
193-
if (partialSecond < 1_000 && !shouldReadTimestampsAsNanoseconds(context))
196+
int partialSecond = p.getIntValue();
197+
if (partialSecond < 1_000 && !shouldReadTimestampsAsNanoseconds(ctxt))
194198
partialSecond *= 1_000_000; // value is milliseconds, convert it to nanoseconds
195-
if (parser.nextToken() != JsonToken.END_ARRAY) {
196-
throw context.wrongTokenException(parser, handledType(), JsonToken.END_ARRAY,
199+
if (p.nextToken() != JsonToken.END_ARRAY) {
200+
throw ctxt.wrongTokenException(p, handledType(), JsonToken.END_ARRAY,
197201
"Expected array to end");
198202
}
199203
result = LocalDateTime.of(year, month, day, hour, minute, second, partialSecond);
200204
}
201205
}
202206
return result;
203207
}
204-
context.reportInputMismatch(handledType(),
208+
ctxt.reportInputMismatch(handledType(),
205209
"Unexpected token (%s) within Array, expected VALUE_NUMBER_INT",
206210
t);
207211
}
208-
if (parser.hasToken(JsonToken.VALUE_EMBEDDED_OBJECT)) {
209-
return (LocalDateTime) parser.getEmbeddedObject();
212+
if (p.hasToken(JsonToken.VALUE_EMBEDDED_OBJECT)) {
213+
return (LocalDateTime) p.getEmbeddedObject();
210214
}
211-
if (parser.hasToken(JsonToken.VALUE_NUMBER_INT)) {
212-
_throwNoNumericTimestampNeedTimeZone(parser, context);
215+
if (p.hasToken(JsonToken.VALUE_NUMBER_INT)) {
216+
_throwNoNumericTimestampNeedTimeZone(p, ctxt);
213217
}
214-
return _handleUnexpectedToken(context, parser, "Expected array or string.");
218+
return _handleUnexpectedToken(ctxt, p, "Expected array or string");
215219
}
216220

217221
protected boolean shouldReadTimestampsAsNanoseconds(DeserializationContext context) {

datetime/src/main/java/com/fasterxml/jackson/datatype/jsr310/deser/LocalTimeDeserializer.java

Lines changed: 32 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -103,69 +103,73 @@ protected JSR310DateTimeDeserializerBase<?> _withFormatOverrides(Deserialization
103103
}
104104

105105
@Override
106-
public LocalTime deserialize(JsonParser parser, DeserializationContext context) throws IOException
106+
public LocalTime deserialize(JsonParser p, DeserializationContext ctxt) throws IOException
107107
{
108-
if (parser.hasToken(JsonToken.VALUE_STRING)) {
109-
return _fromString(parser, context, parser.getText());
108+
if (p.hasToken(JsonToken.VALUE_STRING)) {
109+
return _fromString(p, ctxt, p.getText());
110110
}
111111
// 30-Sep-2020, tatu: New! "Scalar from Object" (mostly for XML)
112-
if (parser.isExpectedStartObjectToken()) {
113-
return _fromString(parser, context,
114-
context.extractScalarFromObject(parser, this, handledType()));
112+
if (p.isExpectedStartObjectToken()) {
113+
// 17-May-2025, tatu: [databind#4656] need to check for `null`
114+
String str = ctxt.extractScalarFromObject(p, this, handledType());
115+
if (str != null) {
116+
return _fromString(p, ctxt, str);
117+
}
118+
return _handleUnexpectedToken(ctxt, p, "Expected array or string");
115119
}
116-
if (parser.isExpectedStartArrayToken()) {
117-
JsonToken t = parser.nextToken();
120+
if (p.isExpectedStartArrayToken()) {
121+
JsonToken t = p.nextToken();
118122
if (t == JsonToken.END_ARRAY) {
119123
return null;
120124
}
121-
if (context.isEnabled(DeserializationFeature.UNWRAP_SINGLE_VALUE_ARRAYS)
125+
if (ctxt.isEnabled(DeserializationFeature.UNWRAP_SINGLE_VALUE_ARRAYS)
122126
&& (t == JsonToken.VALUE_STRING || t==JsonToken.VALUE_EMBEDDED_OBJECT)) {
123-
final LocalTime parsed = deserialize(parser, context);
124-
if (parser.nextToken() != JsonToken.END_ARRAY) {
125-
handleMissingEndArrayForSingle(parser, context);
127+
final LocalTime parsed = deserialize(p, ctxt);
128+
if (p.nextToken() != JsonToken.END_ARRAY) {
129+
handleMissingEndArrayForSingle(p, ctxt);
126130
}
127131
return parsed;
128132
}
129133
if (t == JsonToken.VALUE_NUMBER_INT) {
130-
int hour = parser.getIntValue();
134+
int hour = p.getIntValue();
131135

132-
parser.nextToken();
133-
int minute = parser.getIntValue();
136+
p.nextToken();
137+
int minute = p.getIntValue();
134138
LocalTime result;
135139

136-
t = parser.nextToken();
140+
t = p.nextToken();
137141
if (t == JsonToken.END_ARRAY) {
138142
result = LocalTime.of(hour, minute);
139143
} else {
140-
int second = parser.getIntValue();
141-
t = parser.nextToken();
144+
int second = p.getIntValue();
145+
t = p.nextToken();
142146
if (t == JsonToken.END_ARRAY) {
143147
result = LocalTime.of(hour, minute, second);
144148
} else {
145-
int partialSecond = parser.getIntValue();
146-
if(partialSecond < 1_000 && !shouldReadTimestampsAsNanoseconds(context))
149+
int partialSecond = p.getIntValue();
150+
if(partialSecond < 1_000 && !shouldReadTimestampsAsNanoseconds(ctxt))
147151
partialSecond *= 1_000_000; // value is milliseconds, convert it to nanoseconds
148-
t = parser.nextToken();
152+
t = p.nextToken();
149153
if (t != JsonToken.END_ARRAY) {
150-
throw context.wrongTokenException(parser, handledType(), JsonToken.END_ARRAY,
154+
throw ctxt.wrongTokenException(p, handledType(), JsonToken.END_ARRAY,
151155
"Expected array to end");
152156
}
153157
result = LocalTime.of(hour, minute, second, partialSecond);
154158
}
155159
}
156160
return result;
157161
}
158-
context.reportInputMismatch(handledType(),
162+
ctxt.reportInputMismatch(handledType(),
159163
"Unexpected token (%s) within Array, expected VALUE_NUMBER_INT",
160164
t);
161165
}
162-
if (parser.hasToken(JsonToken.VALUE_EMBEDDED_OBJECT)) {
163-
return (LocalTime) parser.getEmbeddedObject();
166+
if (p.hasToken(JsonToken.VALUE_EMBEDDED_OBJECT)) {
167+
return (LocalTime) p.getEmbeddedObject();
164168
}
165-
if (parser.hasToken(JsonToken.VALUE_NUMBER_INT)) {
166-
_throwNoNumericTimestampNeedTimeZone(parser, context);
169+
if (p.hasToken(JsonToken.VALUE_NUMBER_INT)) {
170+
_throwNoNumericTimestampNeedTimeZone(p, ctxt);
167171
}
168-
return _handleUnexpectedToken(context, parser, "Expected array or string.");
172+
return _handleUnexpectedToken(ctxt, p, "Expected array or string");
169173
}
170174

171175
protected boolean shouldReadTimestampsAsNanoseconds(DeserializationContext context) {

0 commit comments

Comments
 (0)