@@ -57,6 +57,8 @@ public class InstantDeserializer<T extends Temporal>
57
57
private static final long serialVersionUID = 1L ;
58
58
59
59
private final static boolean DEFAULT_NORMALIZE_ZONE_ID = JavaTimeFeature .NORMALIZE_DESERIALIZED_ZONE_ID .enabledByDefault ();
60
+ private final static boolean DEFAULT_ALWAYS_ALLOW_STRINGIFIED_DATE_TIMESTAMPS
61
+ = JavaTimeFeature .ALWAYS_ALLOW_STRINGIFIED_DATE_TIMESTAMPS .enabledByDefault ();
60
62
61
63
/**
62
64
* Constants used to check if ISO 8601 time string is colonless. See [jackson-modules-java8#131]
@@ -72,7 +74,8 @@ public class InstantDeserializer<T extends Temporal>
72
74
a -> Instant .ofEpochSecond (a .integer , a .fraction ),
73
75
null ,
74
76
true , // yes, replace zero offset with Z
75
- DEFAULT_NORMALIZE_ZONE_ID
77
+ DEFAULT_NORMALIZE_ZONE_ID ,
78
+ DEFAULT_ALWAYS_ALLOW_STRINGIFIED_DATE_TIMESTAMPS
76
79
);
77
80
78
81
public static final InstantDeserializer <OffsetDateTime > OFFSET_DATE_TIME = new InstantDeserializer <>(
@@ -82,7 +85,8 @@ public class InstantDeserializer<T extends Temporal>
82
85
a -> OffsetDateTime .ofInstant (Instant .ofEpochSecond (a .integer , a .fraction ), a .zoneId ),
83
86
(d , z ) -> (d .isEqual (OffsetDateTime .MIN ) || d .isEqual (OffsetDateTime .MAX ) ? d : d .withOffsetSameInstant (z .getRules ().getOffset (d .toLocalDateTime ()))),
84
87
true , // yes, replace zero offset with Z
85
- DEFAULT_NORMALIZE_ZONE_ID
88
+ DEFAULT_NORMALIZE_ZONE_ID ,
89
+ DEFAULT_ALWAYS_ALLOW_STRINGIFIED_DATE_TIMESTAMPS
86
90
);
87
91
88
92
public static final InstantDeserializer <ZonedDateTime > ZONED_DATE_TIME = new InstantDeserializer <>(
@@ -92,7 +96,8 @@ public class InstantDeserializer<T extends Temporal>
92
96
a -> ZonedDateTime .ofInstant (Instant .ofEpochSecond (a .integer , a .fraction ), a .zoneId ),
93
97
ZonedDateTime ::withZoneSameInstant ,
94
98
false , // keep zero offset and Z separate since zones explicitly supported
95
- DEFAULT_NORMALIZE_ZONE_ID
99
+ DEFAULT_NORMALIZE_ZONE_ID ,
100
+ DEFAULT_ALWAYS_ALLOW_STRINGIFIED_DATE_TIMESTAMPS
96
101
);
97
102
98
103
protected final Function <FromIntegerArguments , T > fromMilliseconds ;
@@ -130,17 +135,34 @@ public class InstantDeserializer<T extends Temporal>
130
135
* Flag set from
131
136
* {@link com.fasterxml.jackson.datatype.jsr310.JavaTimeFeature#NORMALIZE_DESERIALIZED_ZONE_ID} to
132
137
* determine whether {@link ZoneId} is to be normalized during deserialization.
138
+ *
139
+ * @since 2.16
133
140
*/
134
141
protected final boolean _normalizeZoneId ;
135
142
143
+ /**
144
+ * Flag set from
145
+ * {@link com.fasterxml.jackson.datatype.jsr310.JavaTimeFeature#ALWAYS_ALLOW_STRINGIFIED_DATE_TIMESTAMPS}
146
+ * to determine whether stringified numbers are interpreted as timestamps
147
+ * (enabled) nor not (disabled) in addition to a custom pattern ({code DateTimeFormatter}).
148
+ *<p>
149
+ * NOTE: stringified timestamps are always allowed with default patterns;
150
+ * this flag only affects handling of custom patterns.
151
+ *
152
+ * @since 2.16
153
+ */
154
+ protected final boolean _alwaysAllowStringifiedDateTimestamps ;
155
+
136
156
protected InstantDeserializer (Class <T > supportedType ,
137
157
DateTimeFormatter formatter ,
138
158
Function <TemporalAccessor , T > parsedToValue ,
139
159
Function <FromIntegerArguments , T > fromMilliseconds ,
140
160
Function <FromDecimalArguments , T > fromNanoseconds ,
141
161
BiFunction <T , ZoneId , T > adjust ,
142
162
boolean replaceZeroOffsetAsZ ,
143
- boolean normalizeZoneId )
163
+ boolean normalizeZoneId ,
164
+ boolean readNumericStringsAsTimestamp
165
+ )
144
166
{
145
167
super (supportedType , formatter );
146
168
this .parsedToValue = parsedToValue ;
@@ -151,6 +173,7 @@ protected InstantDeserializer(Class<T> supportedType,
151
173
this ._adjustToContextTZOverride = null ;
152
174
this ._readTimestampsAsNanosOverride = null ;
153
175
_normalizeZoneId = normalizeZoneId ;
176
+ _alwaysAllowStringifiedDateTimestamps = readNumericStringsAsTimestamp ;
154
177
}
155
178
156
179
@ SuppressWarnings ("unchecked" )
@@ -165,6 +188,7 @@ protected InstantDeserializer(InstantDeserializer<T> base, DateTimeFormatter f)
165
188
_adjustToContextTZOverride = base ._adjustToContextTZOverride ;
166
189
_readTimestampsAsNanosOverride = base ._readTimestampsAsNanosOverride ;
167
190
_normalizeZoneId = base ._normalizeZoneId ;
191
+ _alwaysAllowStringifiedDateTimestamps = base ._alwaysAllowStringifiedDateTimestamps ;
168
192
}
169
193
170
194
@ SuppressWarnings ("unchecked" )
@@ -179,6 +203,7 @@ protected InstantDeserializer(InstantDeserializer<T> base, Boolean adjustToConte
179
203
_adjustToContextTZOverride = adjustToContextTimezoneOverride ;
180
204
_readTimestampsAsNanosOverride = base ._readTimestampsAsNanosOverride ;
181
205
_normalizeZoneId = base ._normalizeZoneId ;
206
+ _alwaysAllowStringifiedDateTimestamps = base ._alwaysAllowStringifiedDateTimestamps ;
182
207
}
183
208
184
209
@ SuppressWarnings ("unchecked" )
@@ -193,6 +218,7 @@ protected InstantDeserializer(InstantDeserializer<T> base, DateTimeFormatter f,
193
218
_adjustToContextTZOverride = base ._adjustToContextTZOverride ;
194
219
_readTimestampsAsNanosOverride = base ._readTimestampsAsNanosOverride ;
195
220
_normalizeZoneId = base ._normalizeZoneId ;
221
+ _alwaysAllowStringifiedDateTimestamps = base ._alwaysAllowStringifiedDateTimestamps ;
196
222
}
197
223
198
224
/**
@@ -214,6 +240,7 @@ protected InstantDeserializer(InstantDeserializer<T> base,
214
240
_adjustToContextTZOverride = adjustToContextTimezoneOverride ;
215
241
_readTimestampsAsNanosOverride = readTimestampsAsNanosOverride ;
216
242
_normalizeZoneId = base ._normalizeZoneId ;
243
+ _alwaysAllowStringifiedDateTimestamps = base ._alwaysAllowStringifiedDateTimestamps ;
217
244
}
218
245
219
246
/**
@@ -233,7 +260,7 @@ protected InstantDeserializer(InstantDeserializer<T> base,
233
260
_readTimestampsAsNanosOverride = base ._readTimestampsAsNanosOverride ;
234
261
235
262
_normalizeZoneId = features .isEnabled (JavaTimeFeature .NORMALIZE_DESERIALIZED_ZONE_ID );
236
-
263
+ _alwaysAllowStringifiedDateTimestamps = features . isEnabled ( JavaTimeFeature . ALWAYS_ALLOW_STRINGIFIED_DATE_TIMESTAMPS );
237
264
}
238
265
239
266
@ Override
@@ -251,7 +278,9 @@ protected InstantDeserializer<T> withLeniency(Boolean leniency) {
251
278
252
279
// @since 2.16
253
280
public InstantDeserializer <T > withFeatures (JacksonFeatureSet <JavaTimeFeature > features ) {
254
- if (_normalizeZoneId == features .isEnabled (JavaTimeFeature .NORMALIZE_DESERIALIZED_ZONE_ID )) {
281
+ if ((_normalizeZoneId == features .isEnabled (JavaTimeFeature .NORMALIZE_DESERIALIZED_ZONE_ID ))
282
+ && (_alwaysAllowStringifiedDateTimestamps == features .isEnabled (JavaTimeFeature .ALWAYS_ALLOW_STRINGIFIED_DATE_TIMESTAMPS ))
283
+ ) {
255
284
return this ;
256
285
}
257
286
return new InstantDeserializer <>(this , features );
@@ -343,10 +372,12 @@ protected T _fromString(JsonParser p, DeserializationContext ctxt,
343
372
// handled like "regular" empty (same as pre-2.12)
344
373
return _fromEmptyString (p , ctxt , string );
345
374
}
346
- // only check for other parsing modes if we are using default formatter
347
- if (_formatter == DateTimeFormatter .ISO_INSTANT ||
348
- _formatter == DateTimeFormatter .ISO_OFFSET_DATE_TIME ||
349
- _formatter == DateTimeFormatter .ISO_ZONED_DATE_TIME ) {
375
+ // only check for other parsing modes if we are using default formatter or explicitly asked to
376
+ if (_alwaysAllowStringifiedDateTimestamps ||
377
+ _formatter == DateTimeFormatter .ISO_INSTANT ||
378
+ _formatter == DateTimeFormatter .ISO_OFFSET_DATE_TIME ||
379
+ _formatter == DateTimeFormatter .ISO_ZONED_DATE_TIME
380
+ ) {
350
381
// 22-Jan-2016, [datatype-jsr310#16]: Allow quoted numbers too
351
382
int dots = _countPeriods (string );
352
383
if (dots >= 0 ) { // negative if not simple number
0 commit comments