Source file src/encoding/json/v2_decode.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  // Represents JSON data structure using native Go types: booleans, floats,
     8  // strings, arrays, and maps.
     9  
    10  package json
    11  
    12  import (
    13  	"cmp"
    14  	"fmt"
    15  	"reflect"
    16  	"strconv"
    17  	"strings"
    18  
    19  	"encoding/json/internal/jsonwire"
    20  	"encoding/json/jsontext"
    21  	jsonv2 "encoding/json/v2"
    22  )
    23  
    24  // Unmarshal parses the JSON-encoded data and stores the result
    25  // in the value pointed to by v. If v is nil or not a pointer,
    26  // Unmarshal returns an [InvalidUnmarshalError].
    27  //
    28  // Unmarshal uses the inverse of the encodings that
    29  // [Marshal] uses, allocating maps, slices, and pointers as necessary,
    30  // with the following additional rules:
    31  //
    32  // To unmarshal JSON into a pointer, Unmarshal first handles the case of
    33  // the JSON being the JSON literal null. In that case, Unmarshal sets
    34  // the pointer to nil. Otherwise, Unmarshal unmarshals the JSON into
    35  // the value pointed at by the pointer. If the pointer is nil, Unmarshal
    36  // allocates a new value for it to point to.
    37  //
    38  // The JSON input is decoded according the following rules:
    39  //
    40  //   - If the value type implements [jsonv2.UnmarshalerFrom],
    41  //     then the UnmarshalJSONFrom method is called to decode the JSON value.
    42  //     If the method returns [errors.ErrUnsupported],
    43  //     then the input is decoded according to subsequent rules.
    44  //
    45  //   - If the value type implements [Unmarshaler],
    46  //     then the UnmarshalJSON method is called to decode the JSON value,
    47  //     including when the input is a JSON null.
    48  //
    49  //   - If the value implements [encoding.TextUnmarshaler] and
    50  //     the input is a JSON string, then the UnmarshalText method
    51  //     is called with the unquoted form of the string.
    52  //
    53  // Otherwise, Unmarshal uses the following type-dependent default decodings:
    54  //
    55  // To unmarshal JSON into a struct, Unmarshal matches incoming object
    56  // keys to the keys used by [Marshal] (either the struct field name or its tag),
    57  // preferring an exact match but also accepting a case-insensitive match. By
    58  // default, object keys which don't have a corresponding struct field are
    59  // ignored (see [Decoder.DisallowUnknownFields] for an alternative).
    60  //
    61  // To unmarshal JSON into an interface value,
    62  // Unmarshal stores one of these in the interface value:
    63  //
    64  //   - bool, for JSON booleans
    65  //   - float64, for JSON numbers
    66  //   - string, for JSON strings
    67  //   - []any, for JSON arrays
    68  //   - map[string]any, for JSON objects
    69  //   - nil for JSON null
    70  //
    71  // To unmarshal a JSON array into a slice, Unmarshal decodes each JSON array
    72  // element into the corresponding slice element, reusing existing slice
    73  // elements in-place. The slice grows to accommodate additional elements,
    74  // or is truncated if the JSON array is shorter.
    75  // As a special case, to unmarshal an empty JSON array into a slice,
    76  // Unmarshal replaces the slice with a new empty slice.
    77  //
    78  // To unmarshal a JSON array into a Go array, Unmarshal decodes
    79  // JSON array elements into corresponding Go array elements.
    80  // If the Go array is smaller than the JSON array,
    81  // the additional JSON array elements are discarded.
    82  // If the JSON array is smaller than the Go array,
    83  // the additional Go array elements are set to zero values.
    84  //
    85  // To unmarshal a JSON object into a map, Unmarshal first establishes a map to
    86  // use. If the map is nil, Unmarshal allocates a new map. Otherwise Unmarshal
    87  // reuses the existing map, keeping existing entries. Unmarshal then stores
    88  // key-value pairs from the JSON object into the map. The map's key type must
    89  // either be any string type, an integer, or implement [encoding.TextUnmarshaler].
    90  //
    91  // If the JSON-encoded data contain a syntax error, Unmarshal returns a [SyntaxError].
    92  //
    93  // If a JSON value is not appropriate for a given target type,
    94  // or if a JSON number overflows the target type, Unmarshal
    95  // skips that field and completes the unmarshaling as best it can.
    96  // If no more serious errors are encountered, Unmarshal returns
    97  // an [UnmarshalTypeError] describing the earliest such error. In any
    98  // case, it's not guaranteed that all the remaining fields following
    99  // the problematic one will be unmarshaled into the target object.
   100  //
   101  // The JSON null value unmarshals into an interface, map, pointer, or slice
   102  // by setting that Go value to nil. Because null is often used in JSON to mean
   103  // “not present,” unmarshaling a JSON null into any other Go type has no effect
   104  // on the value and produces no error.
   105  //
   106  // When unmarshaling quoted strings, invalid UTF-8 or
   107  // invalid UTF-16 surrogate pairs are not treated as an error.
   108  // Instead, they are replaced by the Unicode replacement
   109  // character U+FFFD.
   110  func Unmarshal(data []byte, v any) error {
   111  	return jsonv2.Unmarshal(data, v, DefaultOptionsV1())
   112  }
   113  
   114  // Unmarshaler is the interface implemented by types
   115  // that can unmarshal a JSON description of themselves.
   116  // The input can be assumed to be a valid encoding of
   117  // a JSON value. UnmarshalJSON must copy the JSON data
   118  // if it wishes to retain the data after returning.
   119  type Unmarshaler = jsonv2.Unmarshaler
   120  
   121  // An UnmarshalTypeError describes a JSON value that was
   122  // not appropriate for a value of a specific Go type.
   123  type UnmarshalTypeError struct {
   124  	Value  string       // description of JSON value - "bool", "array", "number -5"
   125  	Type   reflect.Type // type of Go value it could not be assigned to
   126  	Offset int64        // error occurred after reading Offset bytes
   127  	Struct string       // name of the root type containing the field
   128  	Field  string       // the full path from root node to the value
   129  	Err    error        // may be nil
   130  }
   131  
   132  func (e *UnmarshalTypeError) Error() string {
   133  	var s string
   134  	if e.Struct != "" || e.Field != "" {
   135  		// The design of UnmarshalTypeError overly assumes a struct-based
   136  		// Go representation for the JSON value.
   137  		// The logic in jsontext represents paths using a JSON Pointer,
   138  		// which is agnostic to the Go type system.
   139  		// Trying to convert a JSON Pointer into an UnmarshalTypeError.Field
   140  		// is difficult. As a heuristic, if the last path token looks like
   141  		// an index into a JSON array (e.g., ".foo.bar.0"),
   142  		// avoid the phrase "Go struct field ".
   143  		intoWhat := "Go struct field "
   144  		i := strings.LastIndexByte(e.Field, '.') + len(".")
   145  		if len(e.Field[i:]) > 0 && strings.TrimRight(e.Field[i:], "0123456789") == "" {
   146  			intoWhat = "" // likely a Go slice or array
   147  		}
   148  		s = "json: cannot unmarshal " + e.Value + " into " + intoWhat + e.Struct + "." + e.Field + " of type " + e.Type.String()
   149  	} else {
   150  		s = "json: cannot unmarshal " + e.Value + " into Go value of type " + e.Type.String()
   151  	}
   152  	if e.Err != nil {
   153  		s += ": " + e.Err.Error()
   154  	}
   155  	return s
   156  }
   157  
   158  func (e *UnmarshalTypeError) Unwrap() error {
   159  	return e.Err
   160  }
   161  
   162  // An UnmarshalFieldError describes a JSON object key that
   163  // led to an unexported (and therefore unwritable) struct field.
   164  //
   165  // Deprecated: No longer used; kept for compatibility.
   166  type UnmarshalFieldError struct {
   167  	Key   string
   168  	Type  reflect.Type
   169  	Field reflect.StructField
   170  }
   171  
   172  func (e *UnmarshalFieldError) Error() string {
   173  	return "json: cannot unmarshal object key " + strconv.Quote(e.Key) + " into unexported field " + e.Field.Name + " of type " + e.Type.String()
   174  }
   175  
   176  // An InvalidUnmarshalError describes an invalid argument passed to [Unmarshal].
   177  // (The argument to [Unmarshal] must be a non-nil pointer.)
   178  type InvalidUnmarshalError struct {
   179  	Type reflect.Type
   180  }
   181  
   182  func (e *InvalidUnmarshalError) Error() string {
   183  	if e.Type == nil {
   184  		return "json: Unmarshal(nil)"
   185  	}
   186  
   187  	if e.Type.Kind() != reflect.Pointer {
   188  		return "json: Unmarshal(non-pointer " + e.Type.String() + ")"
   189  	}
   190  	return "json: Unmarshal(nil " + e.Type.String() + ")"
   191  }
   192  
   193  // A Number represents a JSON number literal.
   194  type Number string
   195  
   196  // String returns the literal text of the number.
   197  func (n Number) String() string { return string(n) }
   198  
   199  // Float64 returns the number as a float64.
   200  func (n Number) Float64() (float64, error) {
   201  	return strconv.ParseFloat(string(n), 64)
   202  }
   203  
   204  // Int64 returns the number as an int64.
   205  func (n Number) Int64() (int64, error) {
   206  	return strconv.ParseInt(string(n), 10, 64)
   207  }
   208  
   209  var numberType = reflect.TypeFor[Number]()
   210  
   211  // MarshalJSONTo implements [jsonv2.MarshalerTo].
   212  func (n Number) MarshalJSONTo(enc *jsontext.Encoder) error {
   213  	opts := enc.Options()
   214  	stringify, _ := jsonv2.GetOption(opts, jsonv2.StringifyNumbers)
   215  	if k, n := enc.StackIndex(enc.StackDepth()); k == '{' && n%2 == 0 {
   216  		stringify = true // expecting a JSON object name
   217  	}
   218  	n = cmp.Or(n, "0")
   219  	var num []byte
   220  	val := enc.AvailableBuffer()
   221  	if stringify {
   222  		val = append(val, '"')
   223  		val = append(val, n...)
   224  		val = append(val, '"')
   225  		num = val[len(`"`) : len(val)-len(`"`)]
   226  	} else {
   227  		val = append(val, n...)
   228  		num = val
   229  	}
   230  	if n, err := jsonwire.ConsumeNumber(num); n != len(num) || err != nil {
   231  		return fmt.Errorf("cannot parse %q as JSON number: %w", val, strconv.ErrSyntax)
   232  	}
   233  	return enc.WriteValue(val)
   234  }
   235  
   236  // UnmarshalJSONFrom implements [jsonv2.UnmarshalerFrom].
   237  func (n *Number) UnmarshalJSONFrom(dec *jsontext.Decoder) error {
   238  	opts := dec.Options()
   239  	stringify, _ := jsonv2.GetOption(opts, jsonv2.StringifyNumbers)
   240  	if k, n := dec.StackIndex(dec.StackDepth()); k == '{' && n%2 == 0 {
   241  		stringify = true // expecting a JSON object name
   242  	}
   243  	val, err := dec.ReadValue()
   244  	if err != nil {
   245  		return err
   246  	}
   247  	val0 := val
   248  	k := val.Kind()
   249  	switch k {
   250  	case 'n':
   251  		if legacy, _ := jsonv2.GetOption(opts, MergeWithLegacySemantics); !legacy {
   252  			*n = ""
   253  		}
   254  		return nil
   255  	case '"':
   256  		verbatim := jsonwire.ConsumeSimpleString(val) == len(val)
   257  		val = jsonwire.UnquoteMayCopy(val, verbatim)
   258  		if n, err := jsonwire.ConsumeNumber(val); n != len(val) || err != nil {
   259  			return &jsonv2.SemanticError{JSONKind: val0.Kind(), JSONValue: val0.Clone(), GoType: numberType, Err: strconv.ErrSyntax}
   260  		}
   261  		*n = Number(val)
   262  		return nil
   263  	case '0':
   264  		if stringify {
   265  			break
   266  		}
   267  		*n = Number(val)
   268  		return nil
   269  	}
   270  	return &jsonv2.SemanticError{JSONKind: k, GoType: numberType}
   271  }
   272  

View as plain text