36
36
// any empty array, slice, map, or string. In contrast, v2 redefines
37
37
// `omitempty` to omit a field if it encodes as an "empty" JSON value,
38
38
// which is defined as a JSON null, or an empty JSON string, object, or array.
39
- // The [OmitEmptyWithLegacyDefinition ] option controls this behavior difference.
39
+ // The [OmitEmptyWithLegacySemantics ] option controls this behavior difference.
40
40
// Note that `omitempty` behaves identically in both v1 and v2 for a
41
41
// Go array, slice, map, or string (assuming no user-defined MarshalJSON method
42
42
// overrides the default representation). Existing usages of `omitempty` on a
66
66
//
67
67
// - In v1, a Go byte array is represented as a JSON array of JSON numbers.
68
68
// In contrast, in v2 a Go byte array is represented as a Base64-encoded JSON string.
69
- // The [FormatBytesWithLegacySemantics ] option controls this behavior difference.
69
+ // The [FormatByteArrayAsArray ] option controls this behavior difference.
70
70
// To explicitly specify a Go struct field to use a particular representation,
71
71
// either the `format:array` or `format:base64` field option can be specified.
72
72
// Field-specified options take precedence over caller-specified options.
118
118
//
119
119
// - In v1, a [time.Duration] is represented as a JSON number containing
120
120
// the decimal number of nanoseconds. In contrast, in v2 a [time.Duration]
121
- // is represented as a JSON string containing the formatted duration
122
- // (e.g., "1h2m3.456s") according to [time.Duration.String].
123
- // The [FormatTimeWithLegacySemantics] option controls this behavior difference.
121
+ // has no default representation and results in a runtime error.
122
+ // The [FormatDurationAsNano] option controls this behavior difference.
124
123
// To explicitly specify a Go struct field to use a particular representation,
125
124
// either the `format:nano` or `format:units` field option can be specified.
126
125
// Field-specified options take precedence over caller-specified options.
172
171
// but the v1 package will forever remain supported.
173
172
package json
174
173
174
+ // TODO(https://go.dev/issue/71631): Update the "Migrating to v2" documentation
175
+ // with default v2 behavior for [time.Duration].
176
+
175
177
import (
176
178
"encoding"
177
179
@@ -204,11 +206,14 @@ type Options = jsonopts.Options
204
206
// It is equivalent to the following boolean options being set to true:
205
207
//
206
208
// - [CallMethodsWithLegacySemantics]
209
+ // - [FormatByteArrayAsArray]
207
210
// - [FormatBytesWithLegacySemantics]
208
- // - [FormatTimeWithLegacySemantics ]
211
+ // - [FormatDurationAsNano ]
209
212
// - [MatchCaseSensitiveDelimiter]
210
213
// - [MergeWithLegacySemantics]
211
- // - [OmitEmptyWithLegacyDefinition]
214
+ // - [OmitEmptyWithLegacySemantics]
215
+ // - [ParseBytesWithLooseRFC4648]
216
+ // - [ParseTimeWithLooseRFC3339]
212
217
// - [ReportErrorsWithLegacySemantics]
213
218
// - [StringifyWithLegacySemantics]
214
219
// - [UnmarshalArrayFromAnyLength]
@@ -278,13 +283,25 @@ func CallMethodsWithLegacySemantics(v bool) Options {
278
283
}
279
284
}
280
285
286
+ // FormatByteArrayAsArray specifies that a Go [N]byte is
287
+ // formatted as as a normal Go array in contrast to the v2 default of
288
+ // formatting [N]byte as using binary data encoding (RFC 4648).
289
+ // If a struct field has a `format` tag option,
290
+ // then the specified formatting takes precedence.
291
+ //
292
+ // This affects either marshaling or unmarshaling.
293
+ // The v1 default is true.
294
+ func FormatByteArrayAsArray (v bool ) Options {
295
+ if v {
296
+ return jsonflags .FormatByteArrayAsArray | 1
297
+ } else {
298
+ return jsonflags .FormatByteArrayAsArray | 0
299
+ }
300
+ }
301
+
281
302
// FormatBytesWithLegacySemantics specifies that handling of
282
303
// []~byte and [N]~byte types follow legacy semantics:
283
304
//
284
- // - A Go [N]~byte is always treated as as a normal Go array
285
- // in contrast to the v2 default of treating [N]byte as
286
- // using some form of binary data encoding (RFC 4648).
287
- //
288
305
// - A Go []~byte is to be treated as using some form of
289
306
// binary data encoding (RFC 4648) in contrast to the v2 default
290
307
// of only treating []byte as such. In particular, v2 does not
@@ -299,12 +316,6 @@ func CallMethodsWithLegacySemantics(v bool) Options {
299
316
// In contrast, the v2 default is to report an error unmarshaling
300
317
// a JSON array when expecting some form of binary data encoding.
301
318
//
302
- // - When unmarshaling, '\r' and '\n' characters are ignored
303
- // within the encoded "base32" and "base64" data.
304
- // In contrast, the v2 default is to report an error in order to be
305
- // strictly compliant with RFC 4648, section 3.3,
306
- // which specifies that non-alphabet characters must be rejected.
307
- //
308
319
// This affects either marshaling or unmarshaling.
309
320
// The v1 default is true.
310
321
func FormatBytesWithLegacySemantics (v bool ) Options {
@@ -315,29 +326,20 @@ func FormatBytesWithLegacySemantics(v bool) Options {
315
326
}
316
327
}
317
328
318
- // FormatTimeWithLegacySemantics specifies that [time] types are formatted
319
- // with legacy semantics:
320
- //
321
- // - When marshaling or unmarshaling, a [time.Duration] is formatted as
322
- // a JSON number representing the number of nanoseconds.
323
- // In contrast, the default v2 behavior uses a JSON string
324
- // with the duration formatted with [time.Duration.String].
325
- // If a duration field has a `format` tag option,
326
- // then the specified formatting takes precedence.
327
- //
328
- // - When unmarshaling, a [time.Time] follows loose adherence to RFC 3339.
329
- // In particular, it permits historically incorrect representations,
330
- // allowing for deviations in hour format, sub-second separator,
331
- // and timezone representation. In contrast, the default v2 behavior
332
- // is to strictly comply with the grammar specified in RFC 3339.
329
+ // FormatDurationAsNano specifies that a [time.Duration] is
330
+ // formatted as a JSON number representing the number of nanoseconds
331
+ // in contrast to the v2 default of reporting an error.
332
+ // If a duration field has a `format` tag option,
333
+ // then the specified formatting takes precedence.
333
334
//
334
335
// This affects either marshaling or unmarshaling.
335
336
// The v1 default is true.
336
- func FormatTimeWithLegacySemantics (v bool ) Options {
337
+ func FormatDurationAsNano (v bool ) Options {
338
+ // TODO(https://go.dev/issue/71631): Update documentation with v2 behavior.
337
339
if v {
338
- return jsonflags .FormatTimeWithLegacySemantics | 1
340
+ return jsonflags .FormatDurationAsNano | 1
339
341
} else {
340
- return jsonflags .FormatTimeWithLegacySemantics | 0
342
+ return jsonflags .FormatDurationAsNano | 0
341
343
}
342
344
}
343
345
@@ -386,7 +388,7 @@ func MergeWithLegacySemantics(v bool) Options {
386
388
}
387
389
}
388
390
389
- // OmitEmptyWithLegacyDefinition specifies that the `omitempty` tag option
391
+ // OmitEmptyWithLegacySemantics specifies that the `omitempty` tag option
390
392
// follows a definition of empty where a field is omitted if the Go value is
391
393
// false, 0, a nil pointer, a nil interface value,
392
394
// or any empty array, slice, map, or string.
@@ -400,11 +402,45 @@ func MergeWithLegacySemantics(v bool) Options {
400
402
//
401
403
// This only affects marshaling and is ignored when unmarshaling.
402
404
// The v1 default is true.
403
- func OmitEmptyWithLegacyDefinition (v bool ) Options {
405
+ func OmitEmptyWithLegacySemantics (v bool ) Options {
406
+ if v {
407
+ return jsonflags .OmitEmptyWithLegacySemantics | 1
408
+ } else {
409
+ return jsonflags .OmitEmptyWithLegacySemantics | 0
410
+ }
411
+ }
412
+
413
+ // ParseBytesWithLooseRFC4648 specifies that when parsing
414
+ // binary data encoded as "base32" or "base64",
415
+ // to ignore the presence of '\r' and '\n' characters.
416
+ // In contrast, the v2 default is to report an error in order to be
417
+ // strictly compliant with RFC 4648, section 3.3,
418
+ // which specifies that non-alphabet characters must be rejected.
419
+ //
420
+ // This only affects unmarshaling and is ignored when marshaling.
421
+ // The v1 default is true.
422
+ func ParseBytesWithLooseRFC4648 (v bool ) Options {
423
+ if v {
424
+ return jsonflags .ParseBytesWithLooseRFC4648 | 1
425
+ } else {
426
+ return jsonflags .ParseBytesWithLooseRFC4648 | 0
427
+ }
428
+ }
429
+
430
+ // ParseTimeWithLooseRFC3339 specifies that a [time.Time]
431
+ // parses according to loose adherence to RFC 3339.
432
+ // In particular, it permits historically incorrect representations,
433
+ // allowing for deviations in hour format, sub-second separator,
434
+ // and timezone representation. In contrast, the default v2 behavior
435
+ // is to strictly comply with the grammar specified in RFC 3339.
436
+ //
437
+ // This only affects unmarshaling and is ignored when marshaling.
438
+ // The v1 default is true.
439
+ func ParseTimeWithLooseRFC3339 (v bool ) Options {
404
440
if v {
405
- return jsonflags .OmitEmptyWithLegacyDefinition | 1
441
+ return jsonflags .ParseTimeWithLooseRFC3339 | 1
406
442
} else {
407
- return jsonflags .OmitEmptyWithLegacyDefinition | 0
443
+ return jsonflags .ParseTimeWithLooseRFC3339 | 0
408
444
}
409
445
}
410
446
0 commit comments