| // 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" |
| "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 and |
| // 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. |
| type MarshalerTo interface { |
| MarshalJSONTo(*jsontext.Encoder) error |
| |
| // TODO: Should users call the MarshalEncode function or |
| // should/can they call this method directly? Does it matter? |
| } |
| |
| // 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. |
| // |
| // 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. |
| type UnmarshalerFrom interface { |
| UnmarshalJSONFrom(*jsontext.Decoder) error |
| |
| // TODO: Should users call the UnmarshalDecode function or |
| // should/can they call this method directly? Does it matter? |
| } |
| |
| 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 = wrapSkipFunc(err, "marshal 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 = wrapSkipFunc(err, "append 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 = wrapSkipFunc(err, "marshal 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 { |
| err = wrapSkipFunc(err, "marshal method") |
| 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 = wrapSkipFunc(err, "unmarshal 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 = wrapSkipFunc(err, "unmarshal 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() |
| 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 { |
| err = wrapSkipFunc(err, "unmarshal method") |
| 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 |
| } |
| } |