Skip to content

encoding/json/v2: support changing whitespace options in MarshalEncode #79559

Description

@dsnet

Proposal Details

In #76440, the jsonv2 working group decided to support changing jsontext options via a MarshalEncode and UnmarshalDecode call. Doing so introduces an edge-case with how whitespace options are handled when changes partway through. For the initial release of json/v2, we will disallow changing whitespace options until we can implement a more cohesive handling of it.

A naive implementation of passing the changed options down to the underlying jsontext.Encoder results in strange results.

For example:

e := jsontext.NewEncoder(os.Stdout, jsontext.Multiline(false))
e.WriteToken(jsontext.BeginArray)
e.WriteToken(jsontext.BeginArray)
e.WriteToken(jsontext.BeginArray)
json.MarshalEncode(e, []int{1, 2, 3}, jsontext.Multiline(true))
e.WriteToken(jsontext.EndArray)
e.WriteToken(jsontext.EndArray)
e.WriteToken(jsontext.EndArray)

which currently prints:

[[[
			[
				1,
				2,
				3
			]]]]

when it should arguably instead print:

[[[[
	1,
	2,
	3
]]]]

Also:

e := jsontext.NewEncoder(os.Stdout, jsontext.Multiline(true))
e.WriteToken(jsontext.BeginArray)
e.WriteToken(jsontext.String("hello"))
json.MarshalEncode(e, []int{1, 2, 3}, jsontext.Multiline(false))
e.WriteToken(jsontext.EndArray)

which currently prints:

[
	"hello",[1,2,3]
]

when it should arguably instead print:

[
	"hello",
	[1,2,3]
]

(note the extra space after the comma).

The proper handling of whitespace should do the following:

  • The whitespace preceding the next JSON value that would be produced by the call to MarshalEncode should use the previous whitespace settings, rather than the one currently specified to MarshalEncode. The encoding of the next JSON value itself should of course respect the whitespace options specified.
  • The number of indents should be based on how the indent characters that have already previously been produced. Today's implementation trivially assumes that the indent cannot be changed and so it just repeats the Indent setting by the current nesting depth.

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    Status
    Post-proposal

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions