k8s.io/kube-openapi@v0.0.0-20240228011516-70dd3763d340/pkg/internal/third_party/go-json-experiment/json/example_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  	"bytes"
     9  	"errors"
    10  	"fmt"
    11  	"io"
    12  	"log"
    13  	"math"
    14  	"net/http"
    15  	"net/netip"
    16  	"os"
    17  	"reflect"
    18  	"strconv"
    19  	"strings"
    20  	"sync/atomic"
    21  	"time"
    22  
    23  	"k8s.io/kube-openapi/pkg/internal/third_party/go-json-experiment/json"
    24  )
    25  
    26  // If a type implements encoding.TextMarshaler and/or encoding.TextUnmarshaler,
    27  // then the MarshalText and UnmarshalText methods are used to encode/decode
    28  // the value to/from a JSON string.
    29  func Example_textMarshal() {
    30  	// Round-trip marshal and unmarshal a hostname map where the netip.Addr type
    31  	// implements both encoding.TextMarshaler and encoding.TextUnmarshaler.
    32  	want := map[netip.Addr]string{
    33  		netip.MustParseAddr("192.168.0.100"): "carbonite",
    34  		netip.MustParseAddr("192.168.0.101"): "obsidian",
    35  		netip.MustParseAddr("192.168.0.102"): "diamond",
    36  	}
    37  	b, err := json.Marshal(&want)
    38  	if err != nil {
    39  		log.Fatal(err)
    40  	}
    41  	var got map[netip.Addr]string
    42  	err = json.Unmarshal(b, &got)
    43  	if err != nil {
    44  		log.Fatal(err)
    45  	}
    46  
    47  	// Sanity check.
    48  	if !reflect.DeepEqual(got, want) {
    49  		log.Fatalf("roundtrip mismatch: got %v, want %v", got, want)
    50  	}
    51  
    52  	// Print the serialized JSON object. Canonicalize the JSON first since
    53  	// Go map entries are not serialized in a deterministic order.
    54  	(*json.RawValue)(&b).Canonicalize()
    55  	(*json.RawValue)(&b).Indent("", "\t") // indent for readability
    56  	fmt.Println(string(b))
    57  
    58  	// Output:
    59  	// {
    60  	// 	"192.168.0.100": "carbonite",
    61  	// 	"192.168.0.101": "obsidian",
    62  	// 	"192.168.0.102": "diamond"
    63  	// }
    64  }
    65  
    66  // By default, JSON object names for Go struct fields are derived from
    67  // the Go field name, but may be specified in the `json` tag.
    68  // Due to JSON's heritage in JavaScript, the most common naming convention
    69  // used for JSON object names is camelCase.
    70  func Example_fieldNames() {
    71  	var value struct {
    72  		// This field is explicitly ignored with the special "-" name.
    73  		Ignored any `json:"-"`
    74  		// No JSON name is not provided, so the Go field name is used.
    75  		GoName any
    76  		// A JSON name is provided without any special characters.
    77  		JSONName any `json:"jsonName"`
    78  		// No JSON name is not provided, so the Go field name is used.
    79  		Option any `json:",nocase"`
    80  		// An empty JSON name specified using an single-quoted string literal.
    81  		Empty any `json:"''"`
    82  		// A dash JSON name specified using an single-quoted string literal.
    83  		Dash any `json:"'-'"`
    84  		// A comma JSON name specified using an single-quoted string literal.
    85  		Comma any `json:"','"`
    86  		// JSON name with quotes specified using a single-quoted string literal.
    87  		Quote any `json:"'\"\\''"`
    88  		// An unexported field is always ignored.
    89  		unexported any
    90  	}
    91  
    92  	b, err := json.Marshal(value)
    93  	if err != nil {
    94  		log.Fatal(err)
    95  	}
    96  	(*json.RawValue)(&b).Indent("", "\t") // indent for readability
    97  	fmt.Println(string(b))
    98  
    99  	// Output:
   100  	// {
   101  	// 	"GoName": null,
   102  	// 	"jsonName": null,
   103  	// 	"Option": null,
   104  	// 	"": null,
   105  	// 	"-": null,
   106  	// 	",": null,
   107  	// 	"\"'": null
   108  	// }
   109  }
   110  
   111  // Unmarshal matches JSON object names with Go struct fields using
   112  // a case-sensitive match, but can be configured to use a case-insensitive
   113  // match with the "nocase" option. This permits unmarshaling from inputs that
   114  // use naming conventions such as camelCase, snake_case, or kebab-case.
   115  func Example_caseSensitivity() {
   116  	// JSON input using various naming conventions.
   117  	const input = `[
   118  		{"firstname": true},
   119  		{"firstName": true},
   120  		{"FirstName": true},
   121  		{"FIRSTNAME": true},
   122  		{"first_name": true},
   123  		{"FIRST_NAME": true},
   124  		{"first-name": true},
   125  		{"FIRST-NAME": true},
   126  		{"unknown": true}
   127  	]`
   128  
   129  	// Without "nocase", Unmarshal looks for an exact match.
   130  	var withcase []struct {
   131  		X bool `json:"firstName"`
   132  	}
   133  	if err := json.Unmarshal([]byte(input), &withcase); err != nil {
   134  		log.Fatal(err)
   135  	}
   136  	fmt.Println(withcase) // exactly 1 match found
   137  
   138  	// With "nocase", Unmarshal looks first for an exact match,
   139  	// then for a case-insensitive match if none found.
   140  	var nocase []struct {
   141  		X bool `json:"firstName,nocase"`
   142  	}
   143  	if err := json.Unmarshal([]byte(input), &nocase); err != nil {
   144  		log.Fatal(err)
   145  	}
   146  	fmt.Println(nocase) // 8 matches found
   147  
   148  	// Output:
   149  	// [{false} {true} {false} {false} {false} {false} {false} {false} {false}]
   150  	// [{true} {true} {true} {true} {true} {true} {true} {true} {false}]
   151  }
   152  
   153  // Go struct fields can be omitted from the output depending on either
   154  // the input Go value or the output JSON encoding of the value.
   155  // The "omitzero" option omits a field if it is the zero Go value or
   156  // implements a "IsZero() bool" method that reports true.
   157  // The "omitempty" option omits a field if it encodes as an empty JSON value,
   158  // which we define as a JSON null or empty JSON string, object, or array.
   159  // In many cases, the behavior of "omitzero" and "omitempty" are equivalent.
   160  // If both provide the desired effect, then using "omitzero" is preferred.
   161  func Example_omitFields() {
   162  	type MyStruct struct {
   163  		Foo string `json:",omitzero"`
   164  		Bar []int  `json:",omitempty"`
   165  		// Both "omitzero" and "omitempty" can be specified together,
   166  		// in which case the field is omitted if either would take effect.
   167  		// This omits the Baz field either if it is a nil pointer or
   168  		// if it would have encoded as an empty JSON object.
   169  		Baz *MyStruct `json:",omitzero,omitempty"`
   170  	}
   171  
   172  	// Demonstrate behavior of "omitzero".
   173  	b, err := json.Marshal(struct {
   174  		Bool         bool        `json:",omitzero"`
   175  		Int          int         `json:",omitzero"`
   176  		String       string      `json:",omitzero"`
   177  		Time         time.Time   `json:",omitzero"`
   178  		Addr         netip.Addr  `json:",omitzero"`
   179  		Struct       MyStruct    `json:",omitzero"`
   180  		SliceNil     []int       `json:",omitzero"`
   181  		Slice        []int       `json:",omitzero"`
   182  		MapNil       map[int]int `json:",omitzero"`
   183  		Map          map[int]int `json:",omitzero"`
   184  		PointerNil   *string     `json:",omitzero"`
   185  		Pointer      *string     `json:",omitzero"`
   186  		InterfaceNil any         `json:",omitzero"`
   187  		Interface    any         `json:",omitzero"`
   188  	}{
   189  		// Bool is omitted since false is the zero value for a Go bool.
   190  		Bool: false,
   191  		// Int is omitted since 0 is the zero value for a Go int.
   192  		Int: 0,
   193  		// String is omitted since "" is the zero value for a Go string.
   194  		String: "",
   195  		// Time is omitted since time.Time.IsZero reports true.
   196  		Time: time.Date(1, 1, 1, 0, 0, 0, 0, time.UTC),
   197  		// Addr is omitted since netip.Addr{} is the zero value for a Go struct.
   198  		Addr: netip.Addr{},
   199  		// Struct is NOT omitted since it is not the zero value for a Go struct.
   200  		Struct: MyStruct{Bar: []int{}, Baz: new(MyStruct)},
   201  		// SliceNil is omitted since nil is the zero value for a Go slice.
   202  		SliceNil: nil,
   203  		// Slice is NOT omitted since []int{} is not the zero value for a Go slice.
   204  		Slice: []int{},
   205  		// MapNil is omitted since nil is the zero value for a Go map.
   206  		MapNil: nil,
   207  		// Map is NOT omitted since map[int]int{} is not the zero value for a Go map.
   208  		Map: map[int]int{},
   209  		// PointerNil is omitted since nil is the zero value for a Go pointer.
   210  		PointerNil: nil,
   211  		// Pointer is NOT omitted since new(string) is not the zero value for a Go pointer.
   212  		Pointer: new(string),
   213  		// InterfaceNil is omitted since nil is the zero value for a Go interface.
   214  		InterfaceNil: nil,
   215  		// Interface is NOT omitted since (*string)(nil) is not the zero value for a Go interface.
   216  		Interface: (*string)(nil),
   217  	})
   218  	if err != nil {
   219  		log.Fatal(err)
   220  	}
   221  	(*json.RawValue)(&b).Indent("", "\t") // indent for readability
   222  	fmt.Println("OmitZero:", string(b))   // outputs "Struct", "Slice", "Map", "Pointer", and "Interface"
   223  
   224  	// Demonstrate behavior of "omitempty".
   225  	b, err = json.Marshal(struct {
   226  		Bool         bool        `json:",omitempty"`
   227  		Int          int         `json:",omitempty"`
   228  		String       string      `json:",omitempty"`
   229  		Time         time.Time   `json:",omitempty"`
   230  		Addr         netip.Addr  `json:",omitempty"`
   231  		Struct       MyStruct    `json:",omitempty"`
   232  		Slice        []int       `json:",omitempty"`
   233  		Map          map[int]int `json:",omitempty"`
   234  		PointerNil   *string     `json:",omitempty"`
   235  		Pointer      *string     `json:",omitempty"`
   236  		InterfaceNil any         `json:",omitempty"`
   237  		Interface    any         `json:",omitempty"`
   238  	}{
   239  		// Bool is NOT omitted since false is not an empty JSON value.
   240  		Bool: false,
   241  		// Int is NOT omitted since 0 is not a empty JSON value.
   242  		Int: 0,
   243  		// String is omitted since "" is an empty JSON string.
   244  		String: "",
   245  		// Time is NOT omitted since this encodes as a non-empty JSON string.
   246  		Time: time.Date(1, 1, 1, 0, 0, 0, 0, time.UTC),
   247  		// Addr is omitted since this encodes as an empty JSON string.
   248  		Addr: netip.Addr{},
   249  		// Struct is omitted since {} is an empty JSON object.
   250  		Struct: MyStruct{Bar: []int{}, Baz: new(MyStruct)},
   251  		// Slice is omitted since [] is an empty JSON array.
   252  		Slice: []int{},
   253  		// Map is omitted since {} is an empty JSON object.
   254  		Map: map[int]int{},
   255  		// PointerNil is ommited since null is an empty JSON value.
   256  		PointerNil: nil,
   257  		// Pointer is omitted since "" is an empty JSON string.
   258  		Pointer: new(string),
   259  		// InterfaceNil is omitted since null is an empty JSON value.
   260  		InterfaceNil: nil,
   261  		// Interface is omitted since null is an empty JSON value.
   262  		Interface: (*string)(nil),
   263  	})
   264  	if err != nil {
   265  		log.Fatal(err)
   266  	}
   267  	(*json.RawValue)(&b).Indent("", "\t") // indent for readability
   268  	fmt.Println("OmitEmpty:", string(b))  // outputs "Bool", "Int", and "Time"
   269  
   270  	// Output:
   271  	// OmitZero: {
   272  	// 	"Struct": {},
   273  	// 	"Slice": [],
   274  	// 	"Map": {},
   275  	// 	"Pointer": "",
   276  	// 	"Interface": null
   277  	// }
   278  	// OmitEmpty: {
   279  	// 	"Bool": false,
   280  	// 	"Int": 0,
   281  	// 	"Time": "0001-01-01T00:00:00Z"
   282  	// }
   283  }
   284  
   285  // JSON objects can be inlined within a parent object similar to
   286  // how Go structs can be embedded within a parent struct.
   287  // The inlining rules are similar to those of Go embedding,
   288  // but operates upon the JSON namespace.
   289  func Example_inlinedFields() {
   290  	// Base is embedded within Container.
   291  	type Base struct {
   292  		// ID is promoted into the JSON object for Container.
   293  		ID string
   294  		// Type is ignored due to presence of Container.Type.
   295  		Type string
   296  		// Time cancels out with Container.Inlined.Time.
   297  		Time time.Time
   298  	}
   299  	// Other is embedded within Container.
   300  	type Other struct{ Cost float64 }
   301  	// Container embeds Base and Other.
   302  	type Container struct {
   303  		// Base is an embedded struct and is implicitly JSON inlined.
   304  		Base
   305  		// Type takes precedence over Base.Type.
   306  		Type int
   307  		// Inlined is a named Go field, but is explicitly JSON inlined.
   308  		Inlined struct {
   309  			// User is promoted into the JSON object for Container.
   310  			User string
   311  			// Time cancels out with Base.Time.
   312  			Time string
   313  		} `json:",inline"`
   314  		// ID does not conflict with Base.ID since the JSON name is different.
   315  		ID string `json:"uuid"`
   316  		// Other is not JSON inlined since it has an explicit JSON name.
   317  		Other `json:"other"`
   318  	}
   319  
   320  	// Format an empty Container to show what fields are JSON serializable.
   321  	var input Container
   322  	b, err := json.Marshal(&input)
   323  	if err != nil {
   324  		log.Fatal(err)
   325  	}
   326  	(*json.RawValue)(&b).Indent("", "\t") // indent for readability
   327  	fmt.Println(string(b))
   328  
   329  	// Output:
   330  	// {
   331  	// 	"ID": "",
   332  	// 	"Type": 0,
   333  	// 	"User": "",
   334  	// 	"uuid": "",
   335  	// 	"other": {
   336  	// 		"Cost": 0
   337  	// 	}
   338  	// }
   339  }
   340  
   341  // Due to version skew, the set of JSON object members known at compile-time
   342  // may differ from the set of members encountered at execution-time.
   343  // As such, it may be useful to have finer grain handling of unknown members.
   344  // This package supports preserving, rejecting, or discarding such members.
   345  func Example_unknownMembers() {
   346  	const input = `{
   347  		"Name": "Teal",
   348  		"Value": "#008080",
   349  		"WebSafe": false
   350  	}`
   351  	type Color struct {
   352  		Name  string
   353  		Value string
   354  
   355  		// Unknown is a Go struct field that holds unknown JSON object members.
   356  		// It is marked as having this behavior with the "unknown" tag option.
   357  		//
   358  		// The type may be a RawValue or map[string]T.
   359  		Unknown json.RawValue `json:",unknown"`
   360  	}
   361  
   362  	// By default, unknown members are stored in a Go field marked as "unknown"
   363  	// or ignored if no such field exists.
   364  	var color Color
   365  	err := json.Unmarshal([]byte(input), &color)
   366  	if err != nil {
   367  		log.Fatal(err)
   368  	}
   369  	fmt.Println("Unknown members:", string(color.Unknown))
   370  
   371  	// Specifying UnmarshalOptions.RejectUnknownMembers causes
   372  	// Unmarshal to reject the presence of any unknown members.
   373  	err = json.UnmarshalOptions{
   374  		RejectUnknownMembers: true,
   375  	}.Unmarshal(json.DecodeOptions{}, []byte(input), new(Color))
   376  	if err != nil {
   377  		fmt.Println("Unmarshal error:", errors.Unwrap(err))
   378  	}
   379  
   380  	// By default, Marshal preserves unknown members stored in
   381  	// a Go struct field marked as "unknown".
   382  	b, err := json.Marshal(color)
   383  	if err != nil {
   384  		log.Fatal(err)
   385  	}
   386  	fmt.Println("Output with unknown members:   ", string(b))
   387  
   388  	// Specifying MarshalOptions.DiscardUnknownMembers causes
   389  	// Marshal to discard any unknown members.
   390  	b, err = json.MarshalOptions{
   391  		DiscardUnknownMembers: true,
   392  	}.Marshal(json.EncodeOptions{}, color)
   393  	if err != nil {
   394  		log.Fatal(err)
   395  	}
   396  	fmt.Println("Output without unknown members:", string(b))
   397  
   398  	// Output:
   399  	// Unknown members: {"WebSafe":false}
   400  	// Unmarshal error: unknown name "WebSafe"
   401  	// Output with unknown members:    {"Name":"Teal","Value":"#008080","WebSafe":false}
   402  	// Output without unknown members: {"Name":"Teal","Value":"#008080"}
   403  }
   404  
   405  // The "format" tag option can be used to alter the formatting of certain types.
   406  func Example_formatFlags() {
   407  	value := struct {
   408  		BytesBase64    []byte         `json:",format:base64"`
   409  		BytesHex       [8]byte        `json:",format:hex"`
   410  		BytesArray     []byte         `json:",format:array"`
   411  		FloatNonFinite float64        `json:",format:nonfinite"`
   412  		MapEmitNull    map[string]any `json:",format:emitnull"`
   413  		SliceEmitNull  []any          `json:",format:emitnull"`
   414  		TimeDateOnly   time.Time      `json:",format:'2006-01-02'"`
   415  		DurationNanos  time.Duration  `json:",format:nanos"`
   416  	}{
   417  		BytesBase64:    []byte{0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef},
   418  		BytesHex:       [8]byte{0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef},
   419  		BytesArray:     []byte{0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef},
   420  		FloatNonFinite: math.NaN(),
   421  		MapEmitNull:    nil,
   422  		SliceEmitNull:  nil,
   423  		TimeDateOnly:   time.Date(2000, 1, 1, 0, 0, 0, 0, time.UTC),
   424  		DurationNanos:  time.Second + time.Millisecond + time.Microsecond + time.Nanosecond,
   425  	}
   426  
   427  	b, err := json.Marshal(&value)
   428  	if err != nil {
   429  		log.Fatal(err)
   430  	}
   431  	(*json.RawValue)(&b).Indent("", "\t") // indent for readability
   432  	fmt.Println(string(b))
   433  
   434  	// Output:
   435  	// {
   436  	// 	"BytesBase64": "ASNFZ4mrze8=",
   437  	// 	"BytesHex": "0123456789abcdef",
   438  	// 	"BytesArray": [
   439  	// 		1,
   440  	// 		35,
   441  	// 		69,
   442  	// 		103,
   443  	// 		137,
   444  	// 		171,
   445  	// 		205,
   446  	// 		239
   447  	// 	],
   448  	// 	"FloatNonFinite": "NaN",
   449  	// 	"MapEmitNull": null,
   450  	// 	"SliceEmitNull": null,
   451  	// 	"TimeDateOnly": "2000-01-01",
   452  	// 	"DurationNanos": 1001001001
   453  	// }
   454  }
   455  
   456  // When implementing HTTP endpoints, it is common to be operating with an
   457  // io.Reader and an io.Writer. The UnmarshalFull and MarshalFull functions
   458  // assist in operating on such input/output types.
   459  // UnmarshalFull reads the entirety of the io.Reader to ensure that io.EOF
   460  // is encountered without any unexpected bytes after the top-level JSON value.
   461  func Example_serveHTTP() {
   462  	// Some global state maintained by the server.
   463  	var n int64
   464  
   465  	// The "add" endpoint accepts a POST request with a JSON object
   466  	// containing a number to atomically add to the server's global counter.
   467  	// It returns the updated value of the counter.
   468  	http.HandleFunc("/api/add", func(w http.ResponseWriter, r *http.Request) {
   469  		// Unmarshal the request from the client.
   470  		var val struct{ N int64 }
   471  		if err := json.UnmarshalFull(r.Body, &val); err != nil {
   472  			// Inability to unmarshal the input suggests a client-side problem.
   473  			http.Error(w, err.Error(), http.StatusBadRequest)
   474  			return
   475  		}
   476  
   477  		// Marshal a response from the server.
   478  		val.N = atomic.AddInt64(&n, val.N)
   479  		if err := json.MarshalFull(w, &val); err != nil {
   480  			// Inability to marshal the output suggests a server-side problem.
   481  			// This error is not always observable by the client since
   482  			// json.MarshalFull may have already written to the output.
   483  			http.Error(w, err.Error(), http.StatusInternalServerError)
   484  			return
   485  		}
   486  	})
   487  }
   488  
   489  // Some Go types have a custom JSON represention where the implementation
   490  // is delegated to some external package. Consequentely, the "json" package
   491  // will not know how to use that external implementation.
   492  // For example, the "google.golang.org/protobuf/encoding/protojson" package
   493  // implements JSON for all "google.golang.org/protobuf/proto".Message types.
   494  // MarshalOptions.Marshalers and UnmarshalOptions.Unmarshalers can be used
   495  // to configure "json" and "protojson" to cooperate together.
   496  func Example_protoJSON() {
   497  	// Let protoMessage be "google.golang.org/protobuf/proto".Message.
   498  	type protoMessage interface{ ProtoReflect() }
   499  	// Let foopbMyMessage be a concrete implementation of proto.Message.
   500  	type foopbMyMessage struct{ protoMessage }
   501  	// Let protojson be an import of "google.golang.org/protobuf/encoding/protojson".
   502  	var protojson struct {
   503  		Marshal   func(protoMessage) ([]byte, error)
   504  		Unmarshal func([]byte, protoMessage) error
   505  	}
   506  
   507  	// This value mixes both non-proto.Message types and proto.Message types.
   508  	// It should use the "json" package to handle non-proto.Message types and
   509  	// should use the "protojson" package to handle proto.Message types.
   510  	var value struct {
   511  		// GoStruct does not implement proto.Message and
   512  		// should use the default behavior of the "json" package.
   513  		GoStruct struct {
   514  			Name string
   515  			Age  int
   516  		}
   517  
   518  		// ProtoMessage implements proto.Message and
   519  		// should be handled using protojson.Marshal.
   520  		ProtoMessage *foopbMyMessage
   521  	}
   522  
   523  	// Marshal using protojson.Marshal for proto.Message types.
   524  	b, err := json.MarshalOptions{
   525  		// Use protojson.Marshal as a type-specific marshaler.
   526  		Marshalers: json.MarshalFuncV1(protojson.Marshal),
   527  	}.Marshal(json.EncodeOptions{}, &value)
   528  	if err != nil {
   529  		log.Fatal(err)
   530  	}
   531  
   532  	// Unmarshal using protojson.Unmarshal for proto.Message types.
   533  	err = json.UnmarshalOptions{
   534  		// Use protojson.Unmarshal as a type-specific unmarshaler.
   535  		Unmarshalers: json.UnmarshalFuncV1(protojson.Unmarshal),
   536  	}.Unmarshal(json.DecodeOptions{}, b, &value)
   537  	if err != nil {
   538  		log.Fatal(err)
   539  	}
   540  }
   541  
   542  // This example demonstrates the use of the Encoder and Decoder to
   543  // parse and modify JSON without unmarshaling it into a concrete Go type.
   544  func Example_stringReplace() {
   545  	// Example input with non-idiomatic use of "Golang" instead of "Go".
   546  	const input = `{
   547  		"title": "Golang version 1 is released",
   548  		"author": "Andrew Gerrand",
   549  		"date": "2012-03-28",
   550  		"text": "Today marks a major milestone in the development of the Golang programming language.",
   551  		"otherArticles": [
   552  			"Twelve Years of Golang",
   553  			"The Laws of Reflection",
   554  			"Learn Golang from your browser"
   555  		]
   556  	}`
   557  
   558  	// Using a Decoder and Encoder, we can parse through every token,
   559  	// check and modify the token if necessary, and
   560  	// write the token to the output.
   561  	var replacements []string
   562  	in := strings.NewReader(input)
   563  	dec := json.NewDecoder(in)
   564  	out := new(bytes.Buffer)
   565  	enc := json.EncodeOptions{Indent: "\t"}.NewEncoder(out) // indent for readability
   566  	for {
   567  		// Read a token from the input.
   568  		tok, err := dec.ReadToken()
   569  		if err != nil {
   570  			if err == io.EOF {
   571  				break
   572  			}
   573  			log.Fatal(err)
   574  		}
   575  
   576  		// Check whether the token contains the string "Golang" and
   577  		// replace each occurence with "Go" instead.
   578  		if tok.Kind() == '"' && strings.Contains(tok.String(), "Golang") {
   579  			replacements = append(replacements, dec.StackPointer())
   580  			tok = json.String(strings.ReplaceAll(tok.String(), "Golang", "Go"))
   581  		}
   582  
   583  		// Write the (possibly modified) token to the output.
   584  		if err := enc.WriteToken(tok); err != nil {
   585  			log.Fatal(err)
   586  		}
   587  	}
   588  
   589  	// Print the list of replacements and the adjusted JSON output.
   590  	if len(replacements) > 0 {
   591  		fmt.Println(`Replaced "Golang" with "Go" in:`)
   592  		for _, where := range replacements {
   593  			fmt.Println("\t" + where)
   594  		}
   595  		fmt.Println()
   596  	}
   597  	fmt.Println("Result:", out.String())
   598  
   599  	// Output:
   600  	// Replaced "Golang" with "Go" in:
   601  	// 	/title
   602  	// 	/text
   603  	// 	/otherArticles/0
   604  	// 	/otherArticles/2
   605  	//
   606  	// Result: {
   607  	// 	"title": "Go version 1 is released",
   608  	// 	"author": "Andrew Gerrand",
   609  	// 	"date": "2012-03-28",
   610  	// 	"text": "Today marks a major milestone in the development of the Go programming language.",
   611  	// 	"otherArticles": [
   612  	// 		"Twelve Years of Go",
   613  	// 		"The Laws of Reflection",
   614  	// 		"Learn Go from your browser"
   615  	// 	]
   616  	// }
   617  }
   618  
   619  // Directly embedding JSON within HTML requires special handling for safety.
   620  // Escape certain runes to prevent JSON directly treated as HTML
   621  // from being able to perform <script> injection.
   622  //
   623  // This example shows how to obtain equivalent behavior provided by the
   624  // "encoding/json" package that is no longer directly supported by this package.
   625  // Newly written code that intermix JSON and HTML should instead be using the
   626  // "github.com/google/safehtml" module for safety purposes.
   627  func ExampleEncodeOptions_escapeHTML() {
   628  	page := struct {
   629  		Title string
   630  		Body  string
   631  	}{
   632  		Title: "Example Embedded Javascript",
   633  		Body:  `<script> console.log("Hello, world!"); </script>`,
   634  	}
   635  
   636  	b, err := json.MarshalOptions{}.Marshal(json.EncodeOptions{
   637  		// Escape certain runes within a JSON string so that
   638  		// JSON will be safe to directly embed inside HTML.
   639  		EscapeRune: func(r rune) bool {
   640  			switch r {
   641  			case '&', '<', '>', '\u2028', '\u2029':
   642  				return true
   643  			default:
   644  				return false
   645  			}
   646  		},
   647  		// Indent the output for readability.
   648  		Indent: "\t",
   649  	}, &page)
   650  	if err != nil {
   651  		log.Fatal(err)
   652  	}
   653  	fmt.Println(string(b))
   654  
   655  	// Output:
   656  	// {
   657  	// 	"Title": "Example Embedded Javascript",
   658  	// 	"Body": "\u003cscript\u003e console.log(\"Hello, world!\"); \u003c/script\u003e"
   659  	// }
   660  }
   661  
   662  // Many error types are not serializable since they tend to be Go structs
   663  // without any exported fields (e.g., errors constructed with errors.New).
   664  // Some applications, may desire to marshal an error as a JSON string
   665  // even if these errors cannot be unmarshaled.
   666  func ExampleMarshalOptions_errors() {
   667  	// Response to serialize with some Go errors encountered.
   668  	response := []struct {
   669  		Result string `json:",omitzero"`
   670  		Error  error  `json:",omitzero"`
   671  	}{
   672  		{Result: "Oranges are a good source of Vitamin C."},
   673  		{Error: &strconv.NumError{Func: "ParseUint", Num: "-1234", Err: strconv.ErrSyntax}},
   674  		{Error: &os.PathError{Op: "ReadFile", Path: "/path/to/secret/file", Err: os.ErrPermission}},
   675  	}
   676  
   677  	b, err := json.MarshalOptions{
   678  		// Intercept every attempt to marshal an error type.
   679  		Marshalers: json.NewMarshalers(
   680  			// Suppose we consider strconv.NumError to be a safe to serialize:
   681  			// this type-specific marshal function intercepts this type
   682  			// and encodes the error message as a JSON string.
   683  			json.MarshalFuncV2(func(opts json.MarshalOptions, enc *json.Encoder, err *strconv.NumError) error {
   684  				return enc.WriteToken(json.String(err.Error()))
   685  			}),
   686  			// Error messages may contain sensitive information that may not
   687  			// be appropriate to serialize. For all errors not handled above,
   688  			// report some generic error message.
   689  			json.MarshalFuncV1(func(error) ([]byte, error) {
   690  				return []byte(`"internal server error"`), nil
   691  			}),
   692  		),
   693  	}.Marshal(json.EncodeOptions{
   694  		Indent: "\t", // indent for readability
   695  	}, &response)
   696  	if err != nil {
   697  		log.Fatal(err)
   698  	}
   699  	fmt.Println(string(b))
   700  
   701  	// Output:
   702  	// [
   703  	// 	{
   704  	// 		"Result": "Oranges are a good source of Vitamin C."
   705  	// 	},
   706  	// 	{
   707  	// 		"Error": "strconv.ParseUint: parsing \"-1234\": invalid syntax"
   708  	// 	},
   709  	// 	{
   710  	// 		"Error": "internal server error"
   711  	// 	}
   712  	// ]
   713  }
   714  
   715  // In some applications, the exact precision of JSON numbers needs to be
   716  // preserved when unmarshaling. This can be accomplished using a type-specific
   717  // unmarshal function that intercepts all any types and pre-populates the
   718  // interface value with a RawValue, which can represent a JSON number exactly.
   719  func ExampleUnmarshalOptions_rawNumber() {
   720  	// Input with JSON numbers beyond the representation of a float64.
   721  	const input = `[false, 1e-1000, 3.141592653589793238462643383279, 1e+1000, true]`
   722  
   723  	var value any
   724  	err := json.UnmarshalOptions{
   725  		// Intercept every attempt to unmarshal into the any type.
   726  		Unmarshalers: json.UnmarshalFuncV2(func(opts json.UnmarshalOptions, dec *json.Decoder, val *any) error {
   727  			// If the next value to be decoded is a JSON number,
   728  			// then provide a concrete Go type to unmarshal into.
   729  			if dec.PeekKind() == '0' {
   730  				*val = json.RawValue(nil)
   731  			}
   732  			// Return SkipFunc to fallback on default unmarshal behavior.
   733  			return json.SkipFunc
   734  		}),
   735  	}.Unmarshal(json.DecodeOptions{}, []byte(input), &value)
   736  	if err != nil {
   737  		log.Fatal(err)
   738  	}
   739  	fmt.Println(value)
   740  
   741  	// Sanity check.
   742  	want := []any{false, json.RawValue("1e-1000"), json.RawValue("3.141592653589793238462643383279"), json.RawValue("1e+1000"), true}
   743  	if !reflect.DeepEqual(value, want) {
   744  		log.Fatalf("value mismatch:\ngot  %v\nwant %v", value, want)
   745  	}
   746  
   747  	// Output:
   748  	// [false 1e-1000 3.141592653589793238462643383279 1e+1000 true]
   749  }
   750  
   751  // When using JSON for parsing configuration files,
   752  // the parsing logic often needs to report an error with a line and column
   753  // indicating where in the input an error occurred.
   754  func ExampleUnmarshalOptions_recordOffsets() {
   755  	// Hypothetical configuration file.
   756  	const input = `[
   757  		{"Source": "192.168.0.100:1234", "Destination": "192.168.0.1:80"},
   758  		{"Source": "192.168.0.251:4004"},
   759  		{"Source": "192.168.0.165:8080", "Destination": "0.0.0.0:80"}
   760  	]`
   761  	type Tunnel struct {
   762  		Source      netip.AddrPort
   763  		Destination netip.AddrPort
   764  
   765  		// ByteOffset is populated during unmarshal with the byte offset
   766  		// within the JSON input of the JSON object for this Go struct.
   767  		ByteOffset int64 `json:"-"` // metadata to be ignored for JSON serialization
   768  	}
   769  
   770  	var tunnels []Tunnel
   771  	err := json.UnmarshalOptions{
   772  		// Intercept every attempt to unmarshal into the Tunnel type.
   773  		Unmarshalers: json.UnmarshalFuncV2(func(opts json.UnmarshalOptions, dec *json.Decoder, tunnel *Tunnel) error {
   774  			// Decoder.InputOffset reports the offset after the last token,
   775  			// but we want to record the offset before the next token.
   776  			//
   777  			// Call Decoder.PeekKind to buffer enough to reach the next token.
   778  			// Add the number of leading whitespace, commas, and colons
   779  			// to locate the start of the next token.
   780  			dec.PeekKind()
   781  			unread := dec.UnreadBuffer()
   782  			n := len(unread) - len(bytes.TrimLeft(unread, " \n\r\t,:"))
   783  			tunnel.ByteOffset = dec.InputOffset() + int64(n)
   784  
   785  			// Return SkipFunc to fallback on default unmarshal behavior.
   786  			return json.SkipFunc
   787  		}),
   788  	}.Unmarshal(json.DecodeOptions{}, []byte(input), &tunnels)
   789  	if err != nil {
   790  		log.Fatal(err)
   791  	}
   792  
   793  	// lineColumn converts a byte offset into a one-indexed line and column.
   794  	// The offset must be within the bounds of the input.
   795  	lineColumn := func(input string, offset int) (line, column int) {
   796  		line = 1 + strings.Count(input[:offset], "\n")
   797  		column = 1 + offset - (strings.LastIndex(input[:offset], "\n") + len("\n"))
   798  		return line, column
   799  	}
   800  
   801  	// Verify that the configuration file is valid.
   802  	for _, tunnel := range tunnels {
   803  		if !tunnel.Source.IsValid() || !tunnel.Destination.IsValid() {
   804  			line, column := lineColumn(input, int(tunnel.ByteOffset))
   805  			fmt.Printf("%d:%d: source and destination must both be specified", line, column)
   806  		}
   807  	}
   808  
   809  	// Output:
   810  	// 3:3: source and destination must both be specified
   811  }