Source file src/encoding/json/v2/example_marshaljson_test.go

     1  // Copyright 2026 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  //go:build goexperiment.jsonv2
     6  
     7  package json_test
     8  
     9  import (
    10  	"fmt"
    11  	"log"
    12  	"maps"
    13  	"slices"
    14  
    15  	"encoding/json/jsontext"
    16  	"encoding/json/v2"
    17  )
    18  
    19  // IntSet is a simple set of numbers, implemented using a map.
    20  type IntSet map[int]struct{}
    21  
    22  // MarshalJSONTo encodes s as a JSON array into enc.
    23  func (s *IntSet) MarshalJSONTo(enc *jsontext.Encoder) error {
    24  	// Encode the set as a JSON array.
    25  	if err := enc.WriteToken(jsontext.BeginArray); err != nil {
    26  		return err
    27  	}
    28  
    29  	keys := maps.Keys(*s)
    30  
    31  	// Go map iteration order is non-deterministic. If the caller has
    32  	// requested deterministic output then we must sort the entries.
    33  	deterministic, _ := json.GetOption(enc.Options(), json.Deterministic)
    34  	if deterministic {
    35  		keys = slices.Values(slices.Sorted(keys))
    36  	}
    37  
    38  	for k := range keys {
    39  		// Call MarshalEncode instead of Write methods on Encoder so
    40  		// that the "json" package can automatically handle any options
    41  		// that may be relevant to the representation of k.
    42  		// In this case, StringifyNumbers may affect whether k is
    43  		// quoted or not.
    44  		if err := json.MarshalEncode(enc, k); err != nil {
    45  			return err
    46  		}
    47  	}
    48  
    49  	if err := enc.WriteToken(jsontext.EndArray); err != nil {
    50  		return err
    51  	}
    52  	return nil
    53  }
    54  
    55  // UnmarshalJSONFrom decodes a JSON array from dec into s.
    56  func (s *IntSet) UnmarshalJSONFrom(dec *jsontext.Decoder) error {
    57  	// Consume start of array.
    58  	if k := dec.PeekKind(); k != '[' {
    59  		// The [json] package automatically populates relevant fields
    60  		// in a [json.SemanticError] to provide additional context.
    61  		return &json.SemanticError{JSONKind: k}
    62  	}
    63  	if _, err := dec.ReadToken(); err != nil {
    64  		return err
    65  	}
    66  
    67  	for dec.PeekKind() != ']' {
    68  		var v int
    69  		// See comment in MarshalJSONTo.
    70  		if err := json.UnmarshalDecode(dec, &v); err != nil {
    71  			return err
    72  		}
    73  		if *s == nil {
    74  			*s = IntSet{}
    75  		}
    76  		(*s)[v] = struct{}{}
    77  	}
    78  
    79  	// Consume end of array.
    80  	if _, err := dec.ReadToken(); err != nil {
    81  		return err
    82  	}
    83  	return nil
    84  }
    85  
    86  // Custom types may define custom marshal behavior with [MarshalerTo].
    87  func ExampleMarshalerTo() {
    88  	set := IntSet{
    89  		1: {},
    90  		2: {},
    91  		3: {},
    92  	}
    93  
    94  	b, err := json.Marshal(&set, json.Deterministic(true))
    95  	if err != nil {
    96  		log.Fatal(err)
    97  	}
    98  
    99  	// Indent output for readability.
   100  	v := jsontext.Value(b)
   101  	v.Indent()
   102  	fmt.Println(string(v))
   103  
   104  	// Output:
   105  	// [
   106  	// 	1,
   107  	// 	2,
   108  	// 	3
   109  	// ]
   110  }
   111  
   112  // Custom types may define custom unmarshal behavior with [UnmarshalerFrom].
   113  func ExampleUnmarshalerFrom() {
   114  	s := "[1,2,3]"
   115  
   116  	var set IntSet
   117  	err := json.Unmarshal([]byte(s), &set)
   118  	if err != nil {
   119  		log.Fatal(err)
   120  	}
   121  
   122  	fmt.Println(set)
   123  
   124  	// Output:
   125  	// map[1:{} 2:{} 3:{}]
   126  }
   127  

View as plain text