aboutsummaryrefslogtreecommitdiff
path: root/src/encoding/json/v2/example_orderedobject_test.go
diff options
context:
space:
mode:
authorDamien Neil <dneil@google.com>2025-04-11 14:19:51 -0700
committerGopher Robot <gobot@golang.org>2025-04-18 08:24:07 -0700
commit0e17905793cb5e0acc323a0cdf3733199d93976a (patch)
treefec117ceb6b56866e6c51e6acd72901cf91717ce /src/encoding/json/v2/example_orderedobject_test.go
parentc889004615b40535ebd5054cbcf2deebdb3a299a (diff)
downloadgo-0e17905793cb5e0acc323a0cdf3733199d93976a.tar.xz
encoding/json: add json/v2 with GOEXPERIMENT=jsonv2 guard
This imports the proposed new v2 JSON API implemented in github.com/go-json-experiment/json as of commit d3c622f1b874954c355e60c8e6b6baa5f60d2fed. When GOEXPERIMENT=jsonv2 is set, the encoding/json/v2 and encoding/jsontext packages are visible, the encoding/json package is implemented in terms of encoding/json/v2, and the encoding/json package include various additional APIs. (See #71497 for details.) When GOEXPERIMENT=jsonv2 is not set, the new API is not present and the encoding/json package is unchanged. The experimental API is not bound by the Go compatibility promise and is expected to evolve as updates are made to the json/v2 proposal. The contents of encoding/json/internal/jsontest/testdata are compressed with zstd v1.5.7 with the -19 option. Fixes #71845 For #71497 Change-Id: Ib8c94e5f0586b6aaa22833190b41cf6ef59f4f01 Reviewed-on: https://go-review.googlesource.com/c/go/+/665796 Auto-Submit: Damien Neil <dneil@google.com> LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com> Reviewed-by: Michael Pratt <mpratt@google.com> Reviewed-by: Joseph Tsai <joetsai@digital-static.net> Reviewed-by: Dmitri Shuralyov <dmitshur@google.com>
Diffstat (limited to 'src/encoding/json/v2/example_orderedobject_test.go')
-rw-r--r--src/encoding/json/v2/example_orderedobject_test.go113
1 files changed, 113 insertions, 0 deletions
diff --git a/src/encoding/json/v2/example_orderedobject_test.go b/src/encoding/json/v2/example_orderedobject_test.go
new file mode 100644
index 0000000000..d68782f725
--- /dev/null
+++ b/src/encoding/json/v2/example_orderedobject_test.go
@@ -0,0 +1,113 @@
+// Copyright 2022 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+//go:build goexperiment.jsonv2
+
+package json_test
+
+import (
+ "fmt"
+ "log"
+ "reflect"
+
+ "encoding/json/jsontext"
+ "encoding/json/v2"
+)
+
+// OrderedObject is an ordered sequence of name/value members in a JSON object.
+//
+// RFC 8259 defines an object as an "unordered collection".
+// JSON implementations need not make "ordering of object members visible"
+// to applications nor will they agree on the semantic meaning of an object if
+// "the names within an object are not unique". For maximum compatibility,
+// applications should avoid relying on ordering or duplicity of object names.
+type OrderedObject[V any] []ObjectMember[V]
+
+// ObjectMember is a JSON object member.
+type ObjectMember[V any] struct {
+ Name string
+ Value V
+}
+
+// MarshalJSONTo encodes obj as a JSON object into enc.
+func (obj *OrderedObject[V]) MarshalJSONTo(enc *jsontext.Encoder) error {
+ if err := enc.WriteToken(jsontext.BeginObject); err != nil {
+ return err
+ }
+ for i := range *obj {
+ member := &(*obj)[i]
+ if err := json.MarshalEncode(enc, &member.Name); err != nil {
+ return err
+ }
+ if err := json.MarshalEncode(enc, &member.Value); err != nil {
+ return err
+ }
+ }
+ if err := enc.WriteToken(jsontext.EndObject); err != nil {
+ return err
+ }
+ return nil
+}
+
+// UnmarshalJSONFrom decodes a JSON object from dec into obj.
+func (obj *OrderedObject[V]) UnmarshalJSONFrom(dec *jsontext.Decoder) error {
+ if k := dec.PeekKind(); k != '{' {
+ return fmt.Errorf("expected object start, but encountered %v", k)
+ }
+ if _, err := dec.ReadToken(); err != nil {
+ return err
+ }
+ for dec.PeekKind() != '}' {
+ *obj = append(*obj, ObjectMember[V]{})
+ member := &(*obj)[len(*obj)-1]
+ if err := json.UnmarshalDecode(dec, &member.Name); err != nil {
+ return err
+ }
+ if err := json.UnmarshalDecode(dec, &member.Value); err != nil {
+ return err
+ }
+ }
+ if _, err := dec.ReadToken(); err != nil {
+ return err
+ }
+ return nil
+}
+
+// The exact order of JSON object can be preserved through the use of a
+// specialized type that implements [MarshalerTo] and [UnmarshalerFrom].
+func Example_orderedObject() {
+ // Round-trip marshal and unmarshal an ordered object.
+ // We expect the order and duplicity of JSON object members to be preserved.
+ // Specify jsontext.AllowDuplicateNames since this object contains "fizz" twice.
+ want := OrderedObject[string]{
+ {"fizz", "buzz"},
+ {"hello", "world"},
+ {"fizz", "wuzz"},
+ }
+ b, err := json.Marshal(&want, jsontext.AllowDuplicateNames(true))
+ if err != nil {
+ log.Fatal(err)
+ }
+ var got OrderedObject[string]
+ err = json.Unmarshal(b, &got, jsontext.AllowDuplicateNames(true))
+ if err != nil {
+ log.Fatal(err)
+ }
+
+ // Sanity check.
+ if !reflect.DeepEqual(got, want) {
+ log.Fatalf("roundtrip mismatch: got %v, want %v", got, want)
+ }
+
+ // Print the serialized JSON object.
+ (*jsontext.Value)(&b).Indent() // indent for readability
+ fmt.Println(string(b))
+
+ // Output:
+ // {
+ // "fizz": "buzz",
+ // "hello": "world",
+ // "fizz": "wuzz"
+ // }
+}