Source file src/encoding/json/v2_encode.go

     1  // Copyright 2010 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 implements encoding and decoding of JSON as defined in
     8  // RFC 7159. The mapping between JSON and Go values is described
     9  // in the documentation for the Marshal and Unmarshal functions.
    10  //
    11  // See [JSON and Go] for an introduction to this package.
    12  //
    13  // # Security Considerations
    14  //
    15  // See the "Security Considerations" section in [encoding/json/v2].
    16  //
    17  // For historical reasons, the default behavior of v1 [encoding/json]
    18  // unfortunately operates with less secure defaults.
    19  // New usages of JSON in Go are encouraged to use [encoding/json/v2] instead.
    20  //
    21  // [JSON and Go]: https://go.dev/blog/json
    22  package json
    23  
    24  import (
    25  	"reflect"
    26  	"strconv"
    27  
    28  	jsonv2 "encoding/json/v2"
    29  )
    30  
    31  // Marshal returns the JSON encoding of v.
    32  //
    33  // Marshal traverses the value v recursively.
    34  //
    35  // The input value is encoded as JSON according the following rules:
    36  //
    37  //   - If the value type implements [jsonv2.MarshalerTo],
    38  //     then the MarshalJSONTo method is called to encode the value.
    39  //     If the method returns [errors.ErrUnsupported],
    40  //     then the input is encoded according to subsequent rules.
    41  //
    42  //   - If the value type implements [Marshaler],
    43  //     then the MarshalJSON method is called to encode the value.
    44  //
    45  //   - If the value type implements [encoding.TextAppender],
    46  //     then the AppendText method is called to encode the value and
    47  //     subsequently encode its result as a JSON string.
    48  //
    49  //   - If the value type implements [encoding.TextMarshaler],
    50  //     then the MarshalText method is called to encode the value and
    51  //     subsequently encode its result as a JSON string.
    52  //
    53  // Otherwise, Marshal uses the following type-dependent default encodings:
    54  //
    55  // Boolean values encode as JSON booleans.
    56  //
    57  // Floating point, integer, and [Number] values encode as JSON numbers.
    58  // NaN and +/-Inf values will return an [UnsupportedValueError].
    59  //
    60  // String values encode as JSON strings coerced to valid UTF-8,
    61  // replacing invalid bytes with the Unicode replacement rune.
    62  // So that the JSON will be safe to embed inside HTML <script> tags,
    63  // the string is encoded using [HTMLEscape],
    64  // which replaces "<", ">", "&", U+2028, and U+2029 are escaped
    65  // to "\u003c","\u003e", "\u0026", "\u2028", and "\u2029".
    66  // This replacement can be disabled when using an [Encoder],
    67  // by calling [Encoder.SetEscapeHTML](false).
    68  //
    69  // Array and slice values encode as JSON arrays, except that
    70  // []byte encodes as a base64-encoded string, and a nil slice
    71  // encodes as the null JSON value.
    72  //
    73  // Struct values encode as JSON objects.
    74  // Each exported struct field becomes a member of the object, using the
    75  // field name as the object key, unless the field is omitted for one of the
    76  // reasons given below.
    77  //
    78  // The encoding of each struct field can be customized by the format string
    79  // stored under the "json" key in the struct field's tag.
    80  // The format string gives the name of the field, possibly followed by a
    81  // comma-separated list of options. The name may be empty in order to
    82  // specify options without overriding the default field name.
    83  //
    84  // The "omitempty" option specifies that the field should be omitted
    85  // from the encoding if the field has an empty value, defined as
    86  // false, 0, a nil pointer, a nil interface value, and any array,
    87  // slice, map, or string of length zero.
    88  //
    89  // As a special case, if the field tag is "-", the field is always omitted.
    90  // JSON names containing commas or quotes, or names identical to "" or "-",
    91  // can be specified using a single-quoted string literal, where the syntax
    92  // is identical to the Go grammar for a double-quoted string literal,
    93  // but instead uses single quotes as the delimiters.
    94  //
    95  // Examples of struct field tags and their meanings:
    96  //
    97  //	// Field appears in JSON as key "myName".
    98  //	Field int `json:"myName"`
    99  //
   100  //	// Field appears in JSON as key "myName" and
   101  //	// the field is omitted from the object if its value is empty,
   102  //	// as defined above.
   103  //	Field int `json:"myName,omitempty"`
   104  //
   105  //	// Field appears in JSON as key "Field" (the default), but
   106  //	// the field is skipped if empty.
   107  //	// Note the leading comma.
   108  //	Field int `json:",omitempty"`
   109  //
   110  //	// Field is ignored by this package.
   111  //	Field int `json:"-"`
   112  //
   113  //	// Field appears in JSON as key "-".
   114  //	Field int `json:"'-'"`
   115  //
   116  // The "omitzero" option specifies that the field should be omitted
   117  // from the encoding if the field has a zero value, according to rules:
   118  //
   119  // 1) If the field type has an "IsZero() bool" method, that will be used to
   120  // determine whether the value is zero.
   121  //
   122  // 2) Otherwise, the value is zero if it is the zero value for its type.
   123  //
   124  // If both "omitempty" and "omitzero" are specified, the field will be omitted
   125  // if the value is either empty or zero (or both).
   126  //
   127  // The "string" option signals that a field is stored as JSON inside a
   128  // JSON-encoded string. It applies only to fields of string, floating point,
   129  // integer, or boolean types. This extra level of encoding is sometimes used
   130  // when communicating with JavaScript programs:
   131  //
   132  //	Int64String int64 `json:",string"`
   133  //
   134  // The key name will be used if it's a non-empty string consisting of
   135  // only Unicode letters, digits, and ASCII punctuation except quotation
   136  // marks, backslash, and comma.
   137  //
   138  // Embedded struct fields are usually marshaled as if their inner exported fields
   139  // were fields in the outer struct, subject to the usual Go visibility rules amended
   140  // as described in the next paragraph.
   141  // An anonymous struct field with a name given in its JSON tag is treated as
   142  // having that name, rather than being anonymous.
   143  // An anonymous struct field of interface type is treated the same as having
   144  // that type as its name, rather than being anonymous.
   145  //
   146  // The Go visibility rules for struct fields are amended for JSON when
   147  // deciding which field to marshal or unmarshal. If there are
   148  // multiple fields at the same level, and that level is the least
   149  // nested (and would therefore be the nesting level selected by the
   150  // usual Go rules), the following extra rules apply:
   151  //
   152  // 1) Of those fields, if any are JSON-tagged, only tagged fields are considered,
   153  // even if there are multiple untagged fields that would otherwise conflict.
   154  //
   155  // 2) If there is exactly one field (tagged or not according to the first rule), that is selected.
   156  //
   157  // 3) Otherwise there are multiple fields, and all are ignored; no error occurs.
   158  //
   159  // Handling of anonymous struct fields is new in Go 1.1.
   160  // Prior to Go 1.1, anonymous struct fields were ignored. To force ignoring of
   161  // an anonymous struct field in both current and earlier versions, give the field
   162  // a JSON tag of "-".
   163  //
   164  // Map values encode as JSON objects. The map's key type must either be a
   165  // string, an integer type, or implement [encoding.TextMarshaler]. The map keys
   166  // are sorted and used as JSON object keys by applying the following rules,
   167  // subject to the UTF-8 coercion described for string values above:
   168  //   - keys of any string type are used directly
   169  //   - keys that implement [encoding.TextMarshaler] are marshaled
   170  //   - integer keys are converted to strings
   171  //
   172  // Pointer values encode as the value pointed to.
   173  // A nil pointer encodes as the null JSON value.
   174  //
   175  // Interface values encode as the value contained in the interface.
   176  // A nil interface value encodes as the null JSON value.
   177  //
   178  // Channel, complex, and function values cannot be encoded in JSON.
   179  // Attempting to encode such a value causes Marshal to return
   180  // an [UnsupportedTypeError].
   181  //
   182  // JSON cannot represent cyclic data structures and Marshal does not
   183  // handle them. Passing cyclic structures to Marshal will result in
   184  // an error.
   185  func Marshal(v any) ([]byte, error) {
   186  	return jsonv2.Marshal(v, DefaultOptionsV1())
   187  }
   188  
   189  // MarshalIndent is like [Marshal] but applies [Indent] to format the output.
   190  // Each JSON element in the output will begin on a new line beginning with prefix
   191  // followed by one or more copies of indent according to the indentation nesting.
   192  func MarshalIndent(v any, prefix, indent string) ([]byte, error) {
   193  	b, err := Marshal(v)
   194  	if err != nil {
   195  		return nil, err
   196  	}
   197  	b, err = appendIndent(nil, b, prefix, indent)
   198  	if err != nil {
   199  		return nil, err
   200  	}
   201  	return b, nil
   202  }
   203  
   204  // Marshaler is the interface implemented by types that
   205  // can marshal themselves into valid JSON.
   206  type Marshaler = jsonv2.Marshaler
   207  
   208  // An UnsupportedTypeError is returned by [Marshal] when attempting
   209  // to encode an unsupported value type.
   210  type UnsupportedTypeError struct {
   211  	Type reflect.Type
   212  }
   213  
   214  func (e *UnsupportedTypeError) Error() string {
   215  	return "json: unsupported type: " + e.Type.String()
   216  }
   217  
   218  // An UnsupportedValueError is returned by [Marshal] when attempting
   219  // to encode an unsupported value.
   220  type UnsupportedValueError struct {
   221  	Value reflect.Value
   222  	Str   string
   223  }
   224  
   225  func (e *UnsupportedValueError) Error() string {
   226  	return "json: unsupported value: " + e.Str
   227  }
   228  
   229  // Before Go 1.2, an InvalidUTF8Error was returned by [Marshal] when
   230  // attempting to encode a string value with invalid UTF-8 sequences.
   231  // As of Go 1.2, [Marshal] instead coerces the string to valid UTF-8 by
   232  // replacing invalid bytes with the Unicode replacement rune U+FFFD.
   233  //
   234  // Deprecated: No longer used; kept for compatibility.
   235  type InvalidUTF8Error struct {
   236  	S string // the whole string value that caused the error
   237  }
   238  
   239  func (e *InvalidUTF8Error) Error() string {
   240  	return "json: invalid UTF-8 in string: " + strconv.Quote(e.S)
   241  }
   242  
   243  // A MarshalerError represents an error from calling a
   244  // [Marshaler.MarshalJSON] or [encoding.TextMarshaler.MarshalText] method.
   245  type MarshalerError struct {
   246  	Type       reflect.Type
   247  	Err        error
   248  	sourceFunc string
   249  }
   250  
   251  func (e *MarshalerError) Error() string {
   252  	srcFunc := e.sourceFunc
   253  	if srcFunc == "" {
   254  		srcFunc = "MarshalJSON"
   255  	}
   256  	return "json: error calling " + srcFunc +
   257  		" for type " + e.Type.String() +
   258  		": " + e.Err.Error()
   259  }
   260  
   261  // Unwrap returns the underlying error.
   262  func (e *MarshalerError) Unwrap() error { return e.Err }
   263  

View as plain text