-
Notifications
You must be signed in to change notification settings - Fork 17.9k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
encoding/json: add Encoder.EncodeToken method #40127
Comments
EncodeToken seems like a nice analog of Decoder.Token. I'm less convinced about ClosingToken. If the program doesn't know what syntax comes next, what business does it have encoding JSON token by token? |
Thanks for the review!
I'm not deeply attached to |
What's the expected flushing behavior for this feature? Do we expect that every call to I see several reasonable semantics:
In my opinion, I think option 3 is the most reasonable. It requires no new API, and has decent performance. Tracking whether the top-level value is complete is logic the |
I also vote for option 3. For structured logging where each log record is typically a top-level JSON object flushing on each object has nice properties. |
I also agree that option 3 seems like the right approach, although it might also be useful to provide an explicit Flush method. |
It seems like people are generally in favor of this (if accepted, it would be for Go 1.17). Do I have that right? |
I'm okay with this API, but I'd like to sanity check the behavior for The documentation currently says:
Since there are no It seems to me that:
Is that correct? |
@dsnet That's a good call. I think you're right, but it would be good to have definite assurance here (and we could mention FormatFloat in the docs too). |
Yes, strconv.FormatFloat produces valid JSON for finite numbers, except perhaps if you use prec=0 with 'f'. |
Based on the discussion above, this seems like a likely accept. |
No change in consensus, so accepted. |
Is there an appetite to change the function name to prevent stutter? I see that |
Change https://go.dev/cl/430235 mentions this issue: |
Hi all, we kicked off a discussion for a possible "encoding/json/v2" package that addresses the spirit of this proposal. |
Currently there is a way to decode JSON token-by-token, but the JSON package does not support encoding tokens that way. It has been stated that just writing the tokens yourself is straightforward enough to do (citation needed), but it's not actually that easy to do.
Here's some code that streams JSON from input to output: https://play.golang.org/p/H6Xl_twRIyC. It's at least 50 lines of code to do the basic streaming functionality, it's easy to get wrong by forgetting to put a colon or a comma in the right place, and if you want indentation or HTML escaping, you have to do it yourself.
I propose that we add an
EncodeToken
method tojson.Encoder
:There would be no way to produce syntactically invalid output (other than truncating the output by not completing the encoded value). The Encoder would keep track of the current state in a stack internally.
An example: if we wanted to stream a large array of JSON objects, we could do:
A slightly more comprehensive example is here
The code to stream a set of JSON values would become considerably simpler: https://play.golang.org/p/Wec5wepCYbE
Completeness validation
It might be useful to provide callers with a final check that their encoded value is in fact complete (that is, no final closing tokens have been omitted). To do that, the following method could be provided:
This method makes it straightforward to check that the object is complete (
if env.ClosingToken == nil
), but also could be used for sanity checks when developing, better errors, or to implement a Flush method that automatically closes all open objects and arrays:Discussion
As with the current
Decoder.Token
implementation,Encoder.EncodeToken
will not be particularly efficient, as it requires passing strings and numbers as strings inside an interface value. I think that this can be considered an orthogonal issue: a solution to theDecoder.Token
garbage issue may also be applied toDecoder.Token
. The symmetry betweenDecoder.Token
andEncoder.EncodeToken
is a useful property which makes this API easier to explain and use, and shouldn’t be discarded lightly, in my view.Once
Encoder.Encode
is invoked, there’s no way to return to streaming mode, for example to encode a large array within aMarshalJSON
method. This is a limitation of thejson.Marshaler
interface, and could potentially be addressed by a fix in that area.It would almost be possible to implement this without adding a method at all by changing the
Encode
method to recognizeDelim
. However, it’s currently valid to pass aDelim
value to encode (it encodes as a number), so this would break backward compatibility. Also, it’s arguably cleaner to have a separation between the low level token API and the higher level Encode API.Related proposals
#33714
The text was updated successfully, but these errors were encountered: