252 lines
9.6 KiB
Go
252 lines
9.6 KiB
Go
// Copyright 2010 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 implements encoding and decoding of JSON as defined in
|
|
// RFC 7159. The mapping between JSON and Go values is described
|
|
// in the documentation for the Marshal and Unmarshal functions.
|
|
//
|
|
// See "JSON and Go" for an introduction to this package:
|
|
// https://golang.org/doc/articles/json_and_go.html
|
|
//
|
|
// # Security Considerations
|
|
//
|
|
// See the "Security Considerations" section in [encoding/json/v2].
|
|
//
|
|
// For historical reasons, the default behavior of v1 [encoding/json]
|
|
// unfortunately operates with less secure defaults.
|
|
// New usages of JSON in Go are encouraged to use [encoding/json/v2] instead.
|
|
package json
|
|
|
|
import (
|
|
"reflect"
|
|
"strconv"
|
|
|
|
jsonv2 "encoding/json/v2"
|
|
)
|
|
|
|
// Marshal returns the JSON encoding of v.
|
|
//
|
|
// Marshal traverses the value v recursively.
|
|
// If an encountered value implements [Marshaler]
|
|
// and is not a nil pointer, Marshal calls [Marshaler.MarshalJSON]
|
|
// to produce JSON. If no [Marshaler.MarshalJSON] method is present but the
|
|
// value implements [encoding.TextMarshaler] instead, Marshal calls
|
|
// [encoding.TextMarshaler.MarshalText] and encodes the result as a JSON string.
|
|
// The nil pointer exception is not strictly necessary
|
|
// but mimics a similar, necessary exception in the behavior of
|
|
// [Unmarshaler.UnmarshalJSON].
|
|
//
|
|
// Otherwise, Marshal uses the following type-dependent default encodings:
|
|
//
|
|
// Boolean values encode as JSON booleans.
|
|
//
|
|
// Floating point, integer, and [Number] values encode as JSON numbers.
|
|
// NaN and +/-Inf values will return an [UnsupportedValueError].
|
|
//
|
|
// String values encode as JSON strings coerced to valid UTF-8,
|
|
// replacing invalid bytes with the Unicode replacement rune.
|
|
// So that the JSON will be safe to embed inside HTML <script> tags,
|
|
// the string is encoded using [HTMLEscape],
|
|
// which replaces "<", ">", "&", U+2028, and U+2029 are escaped
|
|
// to "\u003c","\u003e", "\u0026", "\u2028", and "\u2029".
|
|
// This replacement can be disabled when using an [Encoder],
|
|
// by calling [Encoder.SetEscapeHTML](false).
|
|
//
|
|
// Array and slice values encode as JSON arrays, except that
|
|
// []byte encodes as a base64-encoded string, and a nil slice
|
|
// encodes as the null JSON value.
|
|
//
|
|
// Struct values encode as JSON objects.
|
|
// Each exported struct field becomes a member of the object, using the
|
|
// field name as the object key, unless the field is omitted for one of the
|
|
// reasons given below.
|
|
//
|
|
// The encoding of each struct field can be customized by the format string
|
|
// stored under the "json" key in the struct field's tag.
|
|
// The format string gives the name of the field, possibly followed by a
|
|
// comma-separated list of options. The name may be empty in order to
|
|
// specify options without overriding the default field name.
|
|
//
|
|
// The "omitempty" option specifies that the field should be omitted
|
|
// from the encoding if the field has an empty value, defined as
|
|
// false, 0, a nil pointer, a nil interface value, and any array,
|
|
// slice, map, or string of length zero.
|
|
//
|
|
// As a special case, if the field tag is "-", the field is always omitted.
|
|
// JSON names containing commas or quotes, or names identical to "" or "-",
|
|
// can be specified using a single-quoted string literal, where the syntax
|
|
// is identical to the Go grammar for a double-quoted string literal,
|
|
// but instead uses single quotes as the delimiters.
|
|
//
|
|
// Examples of struct field tags and their meanings:
|
|
//
|
|
// // Field appears in JSON as key "myName".
|
|
// Field int `json:"myName"`
|
|
//
|
|
// // Field appears in JSON as key "myName" and
|
|
// // the field is omitted from the object if its value is empty,
|
|
// // as defined above.
|
|
// Field int `json:"myName,omitempty"`
|
|
//
|
|
// // Field appears in JSON as key "Field" (the default), but
|
|
// // the field is skipped if empty.
|
|
// // Note the leading comma.
|
|
// Field int `json:",omitempty"`
|
|
//
|
|
// // Field is ignored by this package.
|
|
// Field int `json:"-"`
|
|
//
|
|
// // Field appears in JSON as key "-".
|
|
// Field int `json:"'-'"`
|
|
//
|
|
// The "omitzero" option specifies that the field should be omitted
|
|
// from the encoding if the field has a zero value, according to rules:
|
|
//
|
|
// 1) If the field type has an "IsZero() bool" method, that will be used to
|
|
// determine whether the value is zero.
|
|
//
|
|
// 2) Otherwise, the value is zero if it is the zero value for its type.
|
|
//
|
|
// If both "omitempty" and "omitzero" are specified, the field will be omitted
|
|
// if the value is either empty or zero (or both).
|
|
//
|
|
// The "string" option signals that a field is stored as JSON inside a
|
|
// JSON-encoded string. It applies only to fields of string, floating point,
|
|
// integer, or boolean types. This extra level of encoding is sometimes used
|
|
// when communicating with JavaScript programs:
|
|
//
|
|
// Int64String int64 `json:",string"`
|
|
//
|
|
// The key name will be used if it's a non-empty string consisting of
|
|
// only Unicode letters, digits, and ASCII punctuation except quotation
|
|
// marks, backslash, and comma.
|
|
//
|
|
// Embedded struct fields are usually marshaled as if their inner exported fields
|
|
// were fields in the outer struct, subject to the usual Go visibility rules amended
|
|
// as described in the next paragraph.
|
|
// An anonymous struct field with a name given in its JSON tag is treated as
|
|
// having that name, rather than being anonymous.
|
|
// An anonymous struct field of interface type is treated the same as having
|
|
// that type as its name, rather than being anonymous.
|
|
//
|
|
// The Go visibility rules for struct fields are amended for JSON when
|
|
// deciding which field to marshal or unmarshal. If there are
|
|
// multiple fields at the same level, and that level is the least
|
|
// nested (and would therefore be the nesting level selected by the
|
|
// usual Go rules), the following extra rules apply:
|
|
//
|
|
// 1) Of those fields, if any are JSON-tagged, only tagged fields are considered,
|
|
// even if there are multiple untagged fields that would otherwise conflict.
|
|
//
|
|
// 2) If there is exactly one field (tagged or not according to the first rule), that is selected.
|
|
//
|
|
// 3) Otherwise there are multiple fields, and all are ignored; no error occurs.
|
|
//
|
|
// Handling of anonymous struct fields is new in Go 1.1.
|
|
// Prior to Go 1.1, anonymous struct fields were ignored. To force ignoring of
|
|
// an anonymous struct field in both current and earlier versions, give the field
|
|
// a JSON tag of "-".
|
|
//
|
|
// Map values encode as JSON objects. The map's key type must either be a
|
|
// string, an integer type, or implement [encoding.TextMarshaler]. The map keys
|
|
// are sorted and used as JSON object keys by applying the following rules,
|
|
// subject to the UTF-8 coercion described for string values above:
|
|
// - keys of any string type are used directly
|
|
// - keys that implement [encoding.TextMarshaler] are marshaled
|
|
// - integer keys are converted to strings
|
|
//
|
|
// Pointer values encode as the value pointed to.
|
|
// A nil pointer encodes as the null JSON value.
|
|
//
|
|
// Interface values encode as the value contained in the interface.
|
|
// A nil interface value encodes as the null JSON value.
|
|
//
|
|
// Channel, complex, and function values cannot be encoded in JSON.
|
|
// Attempting to encode such a value causes Marshal to return
|
|
// an [UnsupportedTypeError].
|
|
//
|
|
// JSON cannot represent cyclic data structures and Marshal does not
|
|
// handle them. Passing cyclic structures to Marshal will result in
|
|
// an error.
|
|
func Marshal(v any) ([]byte, error) {
|
|
return jsonv2.Marshal(v, DefaultOptionsV1())
|
|
}
|
|
|
|
// MarshalIndent is like [Marshal] but applies [Indent] to format the output.
|
|
// Each JSON element in the output will begin on a new line beginning with prefix
|
|
// followed by one or more copies of indent according to the indentation nesting.
|
|
func MarshalIndent(v any, prefix, indent string) ([]byte, error) {
|
|
b, err := Marshal(v)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
b, err = appendIndent(nil, b, prefix, indent)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
return b, nil
|
|
}
|
|
|
|
// Marshaler is the interface implemented by types that
|
|
// can marshal themselves into valid JSON.
|
|
type Marshaler = jsonv2.Marshaler
|
|
|
|
// An UnsupportedTypeError is returned by [Marshal] when attempting
|
|
// to encode an unsupported value type.
|
|
type UnsupportedTypeError struct {
|
|
Type reflect.Type
|
|
}
|
|
|
|
func (e *UnsupportedTypeError) Error() string {
|
|
return "json: unsupported type: " + e.Type.String()
|
|
}
|
|
|
|
// An UnsupportedValueError is returned by [Marshal] when attempting
|
|
// to encode an unsupported value.
|
|
type UnsupportedValueError struct {
|
|
Value reflect.Value
|
|
Str string
|
|
}
|
|
|
|
func (e *UnsupportedValueError) Error() string {
|
|
return "json: unsupported value: " + e.Str
|
|
}
|
|
|
|
// Before Go 1.2, an InvalidUTF8Error was returned by [Marshal] when
|
|
// attempting to encode a string value with invalid UTF-8 sequences.
|
|
// As of Go 1.2, [Marshal] instead coerces the string to valid UTF-8 by
|
|
// replacing invalid bytes with the Unicode replacement rune U+FFFD.
|
|
//
|
|
// Deprecated: No longer used; kept for compatibility.
|
|
type InvalidUTF8Error struct {
|
|
S string // the whole string value that caused the error
|
|
}
|
|
|
|
func (e *InvalidUTF8Error) Error() string {
|
|
return "json: invalid UTF-8 in string: " + strconv.Quote(e.S)
|
|
}
|
|
|
|
// A MarshalerError represents an error from calling a
|
|
// [Marshaler.MarshalJSON] or [encoding.TextMarshaler.MarshalText] method.
|
|
type MarshalerError struct {
|
|
Type reflect.Type
|
|
Err error
|
|
sourceFunc string
|
|
}
|
|
|
|
func (e *MarshalerError) Error() string {
|
|
srcFunc := e.sourceFunc
|
|
if srcFunc == "" {
|
|
srcFunc = "MarshalJSON"
|
|
}
|
|
return "json: error calling " + srcFunc +
|
|
" for type " + e.Type.String() +
|
|
": " + e.Err.Error()
|
|
}
|
|
|
|
// Unwrap returns the underlying error.
|
|
func (e *MarshalerError) Unwrap() error { return e.Err }
|