k8s.io/kube-openapi@v0.0.0-20240228011516-70dd3763d340/pkg/internal/third_party/go-json-experiment/json/example_orderedobject_test.go (about) 1 // Copyright 2022 The Go Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 package json_test 6 7 import ( 8 "fmt" 9 "log" 10 "reflect" 11 12 "k8s.io/kube-openapi/pkg/internal/third_party/go-json-experiment/json" 13 ) 14 15 // OrderedObject is an ordered sequence of name/value members in a JSON object. 16 // 17 // RFC 8259 defines an object as an "unordered collection". 18 // JSON implementations need not make "ordering of object members visible" 19 // to applications nor will they agree on the semantic meaning of an object if 20 // "the names within an object are not unique". For maximum compatibility, 21 // applications should avoid relying on ordering or duplicity of object names. 22 type OrderedObject[V any] []ObjectMember[V] 23 24 // ObjectMember is a JSON object member. 25 type ObjectMember[V any] struct { 26 Name string 27 Value V 28 } 29 30 // MarshalNextJSON encodes obj as a JSON object into enc. 31 func (obj *OrderedObject[V]) MarshalNextJSON(opts json.MarshalOptions, enc *json.Encoder) error { 32 if err := enc.WriteToken(json.ObjectStart); err != nil { 33 return err 34 } 35 for i := range *obj { 36 member := &(*obj)[i] 37 if err := opts.MarshalNext(enc, &member.Name); err != nil { 38 return err 39 } 40 if err := opts.MarshalNext(enc, &member.Value); err != nil { 41 return err 42 } 43 } 44 if err := enc.WriteToken(json.ObjectEnd); err != nil { 45 return err 46 } 47 return nil 48 } 49 50 // UnmarshalNextJSON decodes a JSON object from dec into obj. 51 func (obj *OrderedObject[V]) UnmarshalNextJSON(opts json.UnmarshalOptions, dec *json.Decoder) error { 52 if k := dec.PeekKind(); k != '{' { 53 return fmt.Errorf("expected object start, but encountered %v", k) 54 } 55 if _, err := dec.ReadToken(); err != nil { 56 return err 57 } 58 for dec.PeekKind() != '}' { 59 *obj = append(*obj, ObjectMember[V]{}) 60 member := &(*obj)[len(*obj)-1] 61 if err := opts.UnmarshalNext(dec, &member.Name); err != nil { 62 return err 63 } 64 if err := opts.UnmarshalNext(dec, &member.Value); err != nil { 65 return err 66 } 67 } 68 if _, err := dec.ReadToken(); err != nil { 69 return err 70 } 71 return nil 72 } 73 74 // The exact order of JSON object can be preserved through the use of a 75 // specialized type that implements MarshalerV2 and UnmarshalerV2. 76 func Example_orderedObject() { 77 // Round-trip marshal and unmarshal an ordered object. 78 // We expect the order and duplicity of JSON object members to be preserved. 79 want := OrderedObject[string]{ 80 {"fizz", "buzz"}, 81 {"hello", "world"}, 82 {"fizz", "wuzz"}, 83 } 84 b, err := json.MarshalOptions{}.Marshal(json.EncodeOptions{ 85 AllowDuplicateNames: true, // since the object contains "fizz" twice 86 }, &want) 87 if err != nil { 88 log.Fatal(err) 89 } 90 var got OrderedObject[string] 91 err = json.UnmarshalOptions{}.Unmarshal(json.DecodeOptions{ 92 AllowDuplicateNames: true, // since the object contains "fizz" twice 93 }, b, &got) 94 if err != nil { 95 log.Fatal(err) 96 } 97 98 // Sanity check. 99 if !reflect.DeepEqual(got, want) { 100 log.Fatalf("roundtrip mismatch: got %v, want %v", got, want) 101 } 102 103 // Print the serialized JSON object. 104 (*json.RawValue)(&b).Indent("", "\t") // indent for readability 105 fmt.Println(string(b)) 106 107 // Output: 108 // { 109 // "fizz": "buzz", 110 // "hello": "world", 111 // "fizz": "wuzz" 112 // } 113 }