Skip to content

Commit ac6c32e

Browse files
authored
Update README.md with how legacy string affect Go strings (#95)
1 parent f92909b commit ac6c32e

File tree

2 files changed

+23
-18
lines changed

2 files changed

+23
-18
lines changed

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -143,7 +143,7 @@ This table shows an overview of the changes:
143143
| -- | -- | ------- |
144144
| JSON object members are unmarshaled into a Go struct using a **case-insensitive name match**. | JSON object members are unmarshaled into a Go struct using a **case-sensitive name match**. | [CaseSensitivity](/v1/diff_test.go#:~:text=TestCaseSensitivity) |
145145
| When marshaling a Go struct, a struct field marked as `omitempty` is omitted if **the field value is an empty Go value**, which is defined as false, 0, a nil pointer, a nil interface value, and any empty array, slice, map, or string. | When marshaling a Go struct, a struct field marked as `omitempty` is omitted if **the field value would encode as an empty JSON value**, which is defined as a JSON null, or an empty JSON string, object, or array. | [OmitEmptyOption](/v1/diff_test.go#:~:text=TestOmitEmptyOption) |
146-
| The `string` option **does affect** Go bools. | The `string` option **does not affect** Go bools. | [StringOption](/v1/diff_test.go#:~:text=TestStringOption) |
146+
| The `string` option **does affect** Go strings and bools. | The `string` option **does not affect** Go strings or bools. | [StringOption](/v1/diff_test.go#:~:text=TestStringOption) |
147147
| The `string` option **does not recursively affect** sub-values of the Go field value. | The `string` option **does recursively affect** sub-values of the Go field value. | [StringOption](/v1/diff_test.go#:~:text=TestStringOption) |
148148
| The `string` option **sometimes accepts** a JSON null escaped within a JSON string. | The `string` option **never accepts** a JSON null escaped within a JSON string. | [StringOption](/v1/diff_test.go#:~:text=TestStringOption) |
149149
| A nil Go slice is marshaled as a **JSON null**. | A nil Go slice is marshaled as an **empty JSON array**. | [NilSlicesAndMaps](/v1/diff_test.go#:~:text=TestNilSlicesAndMaps) |

v1/diff_test.go

Lines changed: 22 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ import (
1414
"time"
1515

1616
jsonv2 "github.com/go-json-experiment/json"
17+
"github.com/go-json-experiment/json/jsontext"
1718
)
1819

1920
// NOTE: This file serves as a list of semantic differences between v1 and v2.
@@ -248,12 +249,11 @@ func addr[T any](v T) *T {
248249
return &v
249250
}
250251

251-
// In v1, the "string" option specifies that Go bools and numeric values are
252-
// encoded within a JSON string when marshaling and are unmarshaled from
253-
// either the native JSON representation (i.e., a JSON bool or number) or
254-
// its native representation escaped within a JSON string.
255-
// The "string" option is not applied recursively, and
256-
// so does not affect bools and numeric values within a Go slice or map, but
252+
// In v1, the "string" option specifies that Go strings, bools, and numeric
253+
// values are encoded within a JSON string when marshaling and
254+
// are unmarshaled from its native representation escaped within a JSON string.
255+
// The "string" option is not applied recursively, and so does not affect
256+
// strings, bools, and numeric values within a Go slice or map, but
257257
// does have special handling to affect the underlying value within a pointer.
258258
// When unmarshaling, the "string" option permits decoding from a JSON null
259259
// escaped within a JSON string in some inconsistent cases.
@@ -265,15 +265,14 @@ func addr[T any](v T) *T {
265265
// and thus affects numeric values within a Go slice or map.
266266
// There is no support for escaped JSON nulls within a JSON string.
267267
//
268-
// The main utility for stringifying JSON primitives (i.e., bools and numbers)
269-
// is because JSON parsers often represents numbers as IEEE 754
270-
// floating-point numbers. This results in a loss of precision when trying to
271-
// represent 64-bit integer values. Consequently, many JSON-based APIs actually
272-
// requires that such values be encoded within a JSON string.
273-
// Given the main utility of stringification is for numeric values,
274-
// v2 limits the effect of the "string" option to just numeric Go types.
275-
// According to all code known by the Go module proxy,
276-
// there are close to zero usages of the "string" option with a Go bool.
268+
// The main utility for stringifying JSON numbers is because JSON parsers
269+
// often represents numbers as IEEE 754 floating-point numbers.
270+
// This results in a loss of precision representing 64-bit integer values.
271+
// Consequently, many JSON-based APIs actually requires that such values
272+
// be encoded within a JSON string. Since the main utility of stringification
273+
// is for numeric values, v2 limits the effect of the "string" option
274+
// to just numeric Go types. According to all code known by the Go module proxy,
275+
// there are close to zero usages of the "string" option on a Go string or bool.
277276
//
278277
// Regarding the recursive application of the "string" option,
279278
// there have been a number of issues filed about users being surprised that
@@ -295,6 +294,7 @@ func addr[T any](v T) *T {
295294
// https://go.dev/issue/50997
296295
func TestStringOption(t *testing.T) {
297296
type Types struct {
297+
String string `json:",string"`
298298
Bool bool `json:",string"`
299299
Int int `json:",string"`
300300
Float float64 `json:",string"`
@@ -312,6 +312,7 @@ func TestStringOption(t *testing.T) {
312312
for _, json := range jsonPackages {
313313
t.Run(path.Join("Marshal", json.Version), func(t *testing.T) {
314314
in := Types{
315+
String: "string",
315316
Bool: true,
316317
Int: 1,
317318
Float: 1,
@@ -325,7 +326,10 @@ func TestStringOption(t *testing.T) {
325326
InterfaceA: nil,
326327
InterfaceB: 1,
327328
}
328-
quote := func(s string) string { return `"` + s + `"` }
329+
quote := func(s string) string {
330+
b, _ := jsontext.AppendQuote(nil, s)
331+
return string(b)
332+
}
329333
quoteOnlyV1 := func(s string) string {
330334
if json.Version == "v1" {
331335
s = quote(s)
@@ -340,7 +344,8 @@ func TestStringOption(t *testing.T) {
340344
}
341345
want := strings.Join([]string{
342346
`{`,
343-
`"Bool":` + quoteOnlyV1("true") + `,`, // in v1, Go bool are also stringified
347+
`"String":` + quoteOnlyV1(`"string"`) + `,`, // in v1, Go strings are also stringified
348+
`"Bool":` + quoteOnlyV1("true") + `,`, // in v1, Go bools are also stringified
344349
`"Int":` + quote("1") + `,`,
345350
`"Float":` + quote("1") + `,`,
346351
`"Map":{"Name":` + quoteOnlyV2("1") + `},`, // in v2, numbers are recursively stringified

0 commit comments

Comments
 (0)