| // Copyright 2020 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 | |
| import ( | |
| "encoding" | |
| "errors" | |
| "io" | |
| "reflect" | |
| "encoding/json/internal" | |
| "encoding/json/internal/jsonflags" | |
| "encoding/json/internal/jsonopts" | |
| "encoding/json/internal/jsonwire" | |
| "encoding/json/jsontext" | |
| ) | |
| var errNonStringValue = errors.New("JSON value must be string type") | |
| // Interfaces for custom serialization. | |
| var ( | |
| jsonMarshalerType = reflect.TypeFor[Marshaler]() | |
| jsonMarshalerToType = reflect.TypeFor[MarshalerTo]() | |
| jsonUnmarshalerType = reflect.TypeFor[Unmarshaler]() | |
| jsonUnmarshalerFromType = reflect.TypeFor[UnmarshalerFrom]() | |
| textAppenderType = reflect.TypeFor[encoding.TextAppender]() | |
| textMarshalerType = reflect.TypeFor[encoding.TextMarshaler]() | |
| textUnmarshalerType = reflect.TypeFor[encoding.TextUnmarshaler]() | |
| allMarshalerTypes = []reflect.Type{jsonMarshalerToType, jsonMarshalerType, textAppenderType, textMarshalerType} | |
| allUnmarshalerTypes = []reflect.Type{jsonUnmarshalerFromType, jsonUnmarshalerType, textUnmarshalerType} | |
| allMethodTypes = append(allMarshalerTypes, allUnmarshalerTypes...) | |
| ) | |
| // Marshaler is implemented by types that can marshal themselves. | |
| // It is recommended that types implement [MarshalerTo] unless the implementation | |
| // is trying to avoid a hard dependency on the "jsontext" package. | |
| // | |
| // It is recommended that implementations return a buffer that is safe | |
| // for the caller to retain and potentially mutate. | |
| // | |
| // If the returned error is a [SemanticError], then unpopulated fields | |
| // of the error may be populated by [json] with additional context. | |
| // Errors of other types are wrapped within a [SemanticError]. | |
| type Marshaler interface { | |
| MarshalJSON() ([]byte, error) | |
| } | |
| // MarshalerTo is implemented by types that can marshal themselves. | |
| // It is recommended that types implement MarshalerTo instead of [Marshaler] | |
| // since this is both more performant and flexible. | |
| // If a type implements both Marshaler and MarshalerTo, | |
| // then MarshalerTo takes precedence. In such a case, both implementations | |
| // should aim to have equivalent behavior for the default marshal options. | |
| // | |
| // The implementation must write only one JSON value to the Encoder. | |
| // Alternatively, it may return [errors.ErrUnsupported] without mutating | |
| // the Encoder. The "json" package calling the method will | |
| // use the next available JSON representation for the receiver type. | |
| // Implementations must not retain the pointer to [jsontext.Encoder]. | |
| // | |
| // If the returned error is a [SemanticError], then unpopulated fields | |
| // of the error may be populated by [json] with additional context. | |
| // Errors of other types are wrapped within a [SemanticError], | |
| // unless it is an IO error. | |
| // | |
| // The MarshalJSONTo method should not be directly called as it may | |
| // return sentinel errors that need special handling. | |
| // Users should instead call [MarshalEncode], which handles such cases. | |
| type MarshalerTo interface { | |
| MarshalJSONTo(*jsontext.Encoder) error | |
| } | |
| // Unmarshaler is implemented by types that can unmarshal themselves. | |
| // It is recommended that types implement [UnmarshalerFrom] unless the implementation | |
| // is trying to avoid a hard dependency on the "jsontext" package. | |
| // | |
| // The input can be assumed to be a valid encoding of a JSON value | |
| // if called from unmarshal functionality in this package. | |
| // UnmarshalJSON must copy the JSON data if it is retained after returning. | |
| // It is recommended that UnmarshalJSON implement merge semantics when | |
| // unmarshaling into a pre-populated value. | |
| // | |
| // Implementations must not retain or mutate the input []byte. | |
| // | |
| // If the returned error is a [SemanticError], then unpopulated fields | |
| // of the error may be populated by [json] with additional context. | |
| // Errors of other types are wrapped within a [SemanticError]. | |
| type Unmarshaler interface { | |
| UnmarshalJSON([]byte) error | |
| } | |
| // UnmarshalerFrom is implemented by types that can unmarshal themselves. | |
| // It is recommended that types implement UnmarshalerFrom instead of [Unmarshaler] | |
| // since this is both more performant and flexible. | |
| // If a type implements both Unmarshaler and UnmarshalerFrom, | |
| // then UnmarshalerFrom takes precedence. In such a case, both implementations | |
| // should aim to have equivalent behavior for the default unmarshal options. | |
| // | |
| // The implementation must read only one JSON value from the Decoder. | |
| // It is recommended that UnmarshalJSONFrom implement merge semantics when | |
| // unmarshaling into a pre-populated value. | |
| // Alternatively, it may return [errors.ErrUnsupported] without mutating | |
| // the Decoder. The "json" package calling the method will | |
| // use the next available JSON representation for the receiver type. | |
| // Implementations must not retain the pointer to [jsontext.Decoder]. | |
| // | |
| // If the returned error is a [SemanticError], then unpopulated fields | |
| // of the error may be populated by [json] with additional context. | |
| // Errors of other types are wrapped within a [SemanticError], | |
| // unless it is a [jsontext.SyntacticError] or an IO error. | |
| // | |
| // The UnmarshalJSONFrom method should not be directly called as it may | |
| // return sentinel errors that need special handling. | |
| // Users should instead call [UnmarshalDecode], which handles such cases. | |
| type UnmarshalerFrom interface { | |
| UnmarshalJSONFrom(*jsontext.Decoder) error | |
| } | |
| func makeMethodArshaler(fncs *arshaler, t reflect.Type) *arshaler { | |
| // Avoid injecting method arshaler on the pointer or interface version | |
| // to avoid ever calling the method on a nil pointer or interface receiver. | |
| // Let it be injected on the value receiver (which is always addressable). | |
| if t.Kind() == reflect.Pointer || t.Kind() == reflect.Interface { | |
| return fncs | |
| } | |
| if needAddr, ok := implements(t, textMarshalerType); ok { | |
| fncs.nonDefault = true | |
| prevMarshal := fncs.marshal | |
| fncs.marshal = func(enc *jsontext.Encoder, va addressableValue, mo *jsonopts.Struct) error { | |
| if mo.Flags.Get(jsonflags.CallMethodsWithLegacySemantics) && | |
| (needAddr && va.forcedAddr) { | |
| return prevMarshal(enc, va, mo) | |
| } | |
| marshaler, _ := reflect.TypeAssert[encoding.TextMarshaler](va.Addr()) | |
| if err := export.Encoder(enc).AppendRaw('"', false, func(b []byte) ([]byte, error) { | |
| b2, err := marshaler.MarshalText() | |
| return append(b, b2...), err | |
| }); err != nil { | |
| err = wrapErrUnsupported(err, "MarshalText method") | |
| if mo.Flags.Get(jsonflags.ReportErrorsWithLegacySemantics) { | |
| return internal.NewMarshalerError(va.Addr().Interface(), err, "MarshalText") // unlike unmarshal, always wrapped | |
| } | |
| if !isSemanticError(err) && !export.IsIOError(err) { | |
| err = newMarshalErrorBefore(enc, t, err) | |
| } | |
| return err | |
| } | |
| return nil | |
| } | |
| } | |
| if needAddr, ok := implements(t, textAppenderType); ok { | |
| fncs.nonDefault = true | |
| prevMarshal := fncs.marshal | |
| fncs.marshal = func(enc *jsontext.Encoder, va addressableValue, mo *jsonopts.Struct) (err error) { | |
| if mo.Flags.Get(jsonflags.CallMethodsWithLegacySemantics) && | |
| (needAddr && va.forcedAddr) { | |
| return prevMarshal(enc, va, mo) | |
| } | |
| appender, _ := reflect.TypeAssert[encoding.TextAppender](va.Addr()) | |
| if err := export.Encoder(enc).AppendRaw('"', false, appender.AppendText); err != nil { | |
| err = wrapErrUnsupported(err, "AppendText method") | |
| if mo.Flags.Get(jsonflags.ReportErrorsWithLegacySemantics) { | |
| return internal.NewMarshalerError(va.Addr().Interface(), err, "AppendText") // unlike unmarshal, always wrapped | |
| } | |
| if !isSemanticError(err) && !export.IsIOError(err) { | |
| err = newMarshalErrorBefore(enc, t, err) | |
| } | |
| return err | |
| } | |
| return nil | |
| } | |
| } | |
| if needAddr, ok := implements(t, jsonMarshalerType); ok { | |
| fncs.nonDefault = true | |
| prevMarshal := fncs.marshal | |
| fncs.marshal = func(enc *jsontext.Encoder, va addressableValue, mo *jsonopts.Struct) error { | |
| if mo.Flags.Get(jsonflags.CallMethodsWithLegacySemantics) && | |
| ((needAddr && va.forcedAddr) || export.Encoder(enc).Tokens.Last.NeedObjectName()) { | |
| return prevMarshal(enc, va, mo) | |
| } | |
| marshaler, _ := reflect.TypeAssert[Marshaler](va.Addr()) | |
| val, err := marshaler.MarshalJSON() | |
| if err != nil { | |
| err = wrapErrUnsupported(err, "MarshalJSON method") | |
| if mo.Flags.Get(jsonflags.ReportErrorsWithLegacySemantics) { | |
| return internal.NewMarshalerError(va.Addr().Interface(), err, "MarshalJSON") // unlike unmarshal, always wrapped | |
| } | |
| err = newMarshalErrorBefore(enc, t, err) | |
| return collapseSemanticErrors(err) | |
| } | |
| if err := enc.WriteValue(val); err != nil { | |
| if mo.Flags.Get(jsonflags.ReportErrorsWithLegacySemantics) { | |
| return internal.NewMarshalerError(va.Addr().Interface(), err, "MarshalJSON") // unlike unmarshal, always wrapped | |
| } | |
| if isSyntacticError(err) { | |
| err = newMarshalErrorBefore(enc, t, err) | |
| } | |
| return err | |
| } | |
| return nil | |
| } | |
| } | |
| if needAddr, ok := implements(t, jsonMarshalerToType); ok { | |
| fncs.nonDefault = true | |
| prevMarshal := fncs.marshal | |
| fncs.marshal = func(enc *jsontext.Encoder, va addressableValue, mo *jsonopts.Struct) error { | |
| if mo.Flags.Get(jsonflags.CallMethodsWithLegacySemantics) && | |
| ((needAddr && va.forcedAddr) || export.Encoder(enc).Tokens.Last.NeedObjectName()) { | |
| return prevMarshal(enc, va, mo) | |
| } | |
| xe := export.Encoder(enc) | |
| prevDepth, prevLength := xe.Tokens.DepthLength() | |
| xe.Flags.Set(jsonflags.WithinArshalCall | 1) | |
| marshaler, _ := reflect.TypeAssert[MarshalerTo](va.Addr()) | |
| err := marshaler.MarshalJSONTo(enc) | |
| xe.Flags.Set(jsonflags.WithinArshalCall | 0) | |
| currDepth, currLength := xe.Tokens.DepthLength() | |
| if (prevDepth != currDepth || prevLength+1 != currLength) && err == nil { | |
| err = errNonSingularValue | |
| } | |
| if err != nil { | |
| if errors.Is(err, errors.ErrUnsupported) { | |
| if prevDepth == currDepth && prevLength == currLength { | |
| return prevMarshal(enc, va, mo) | |
| } | |
| err = errUnsupportedMutation | |
| } | |
| if mo.Flags.Get(jsonflags.ReportErrorsWithLegacySemantics) { | |
| return internal.NewMarshalerError(va.Addr().Interface(), err, "MarshalJSONTo") // unlike unmarshal, always wrapped | |
| } | |
| if !export.IsIOError(err) { | |
| err = newSemanticErrorWithPosition(enc, t, prevDepth, prevLength, err) | |
| } | |
| return err | |
| } | |
| return nil | |
| } | |
| } | |
| if _, ok := implements(t, textUnmarshalerType); ok { | |
| fncs.nonDefault = true | |
| fncs.unmarshal = func(dec *jsontext.Decoder, va addressableValue, uo *jsonopts.Struct) error { | |
| xd := export.Decoder(dec) | |
| var flags jsonwire.ValueFlags | |
| val, err := xd.ReadValue(&flags) | |
| if err != nil { | |
| return err // must be a syntactic or I/O error | |
| } | |
| if val.Kind() == 'n' { | |
| if !uo.Flags.Get(jsonflags.MergeWithLegacySemantics) { | |
| va.SetZero() | |
| } | |
| return nil | |
| } | |
| if val.Kind() != '"' { | |
| return newUnmarshalErrorAfter(dec, t, errNonStringValue) | |
| } | |
| s := jsonwire.UnquoteMayCopy(val, flags.IsVerbatim()) | |
| unmarshaler, _ := reflect.TypeAssert[encoding.TextUnmarshaler](va.Addr()) | |
| if err := unmarshaler.UnmarshalText(s); err != nil { | |
| err = wrapErrUnsupported(err, "UnmarshalText method") | |
| if uo.Flags.Get(jsonflags.ReportErrorsWithLegacySemantics) { | |
| return err // unlike marshal, never wrapped | |
| } | |
| if !isSemanticError(err) && !isSyntacticError(err) && !export.IsIOError(err) { | |
| err = newUnmarshalErrorAfter(dec, t, err) | |
| } | |
| return err | |
| } | |
| return nil | |
| } | |
| } | |
| if _, ok := implements(t, jsonUnmarshalerType); ok { | |
| fncs.nonDefault = true | |
| prevUnmarshal := fncs.unmarshal | |
| fncs.unmarshal = func(dec *jsontext.Decoder, va addressableValue, uo *jsonopts.Struct) error { | |
| if uo.Flags.Get(jsonflags.CallMethodsWithLegacySemantics) && | |
| export.Decoder(dec).Tokens.Last.NeedObjectName() { | |
| return prevUnmarshal(dec, va, uo) | |
| } | |
| val, err := dec.ReadValue() | |
| if err != nil { | |
| return err // must be a syntactic or I/O error | |
| } | |
| unmarshaler, _ := reflect.TypeAssert[Unmarshaler](va.Addr()) | |
| if err := unmarshaler.UnmarshalJSON(val); err != nil { | |
| err = wrapErrUnsupported(err, "UnmarshalJSON method") | |
| if uo.Flags.Get(jsonflags.ReportErrorsWithLegacySemantics) { | |
| return err // unlike marshal, never wrapped | |
| } | |
| err = newUnmarshalErrorAfter(dec, t, err) | |
| return collapseSemanticErrors(err) | |
| } | |
| return nil | |
| } | |
| } | |
| if _, ok := implements(t, jsonUnmarshalerFromType); ok { | |
| fncs.nonDefault = true | |
| prevUnmarshal := fncs.unmarshal | |
| fncs.unmarshal = func(dec *jsontext.Decoder, va addressableValue, uo *jsonopts.Struct) error { | |
| if uo.Flags.Get(jsonflags.CallMethodsWithLegacySemantics) && | |
| export.Decoder(dec).Tokens.Last.NeedObjectName() { | |
| return prevUnmarshal(dec, va, uo) | |
| } | |
| xd := export.Decoder(dec) | |
| prevDepth, prevLength := xd.Tokens.DepthLength() | |
| if prevDepth == 1 && xd.AtEOF() { | |
| return io.EOF // check EOF early to avoid fn reporting an EOF | |
| } | |
| xd.Flags.Set(jsonflags.WithinArshalCall | 1) | |
| unmarshaler, _ := reflect.TypeAssert[UnmarshalerFrom](va.Addr()) | |
| err := unmarshaler.UnmarshalJSONFrom(dec) | |
| xd.Flags.Set(jsonflags.WithinArshalCall | 0) | |
| currDepth, currLength := xd.Tokens.DepthLength() | |
| if (prevDepth != currDepth || prevLength+1 != currLength) && err == nil { | |
| err = errNonSingularValue | |
| } | |
| if err != nil { | |
| if errors.Is(err, errors.ErrUnsupported) { | |
| if prevDepth == currDepth && prevLength == currLength { | |
| return prevUnmarshal(dec, va, uo) | |
| } | |
| err = errUnsupportedMutation | |
| } | |
| if uo.Flags.Get(jsonflags.ReportErrorsWithLegacySemantics) { | |
| if err2 := xd.SkipUntil(prevDepth, prevLength+1); err2 != nil { | |
| return err2 | |
| } | |
| return err // unlike marshal, never wrapped | |
| } | |
| if !isSyntacticError(err) && !export.IsIOError(err) { | |
| err = newSemanticErrorWithPosition(dec, t, prevDepth, prevLength, err) | |
| } | |
| return err | |
| } | |
| return nil | |
| } | |
| } | |
| return fncs | |
| } | |
| // implementsAny is like t.Implements(ifaceType) for a list of interfaces, | |
| // but checks whether either t or reflect.PointerTo(t) implements the interface. | |
| func implementsAny(t reflect.Type, ifaceTypes ...reflect.Type) bool { | |
| for _, ifaceType := range ifaceTypes { | |
| if _, ok := implements(t, ifaceType); ok { | |
| return true | |
| } | |
| } | |
| return false | |
| } | |
| // implements is like t.Implements(ifaceType) but checks whether | |
| // either t or reflect.PointerTo(t) implements the interface. | |
| // It also reports whether the value needs to be addressed | |
| // in order to satisfy the interface. | |
| func implements(t, ifaceType reflect.Type) (needAddr, ok bool) { | |
| switch { | |
| case t.Implements(ifaceType): | |
| return false, true | |
| case reflect.PointerTo(t).Implements(ifaceType): | |
| return true, true | |
| default: | |
| return false, false | |
| } | |
| } |