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

View as plain text