| | |
| | |
| | |
| |
|
| | |
| |
|
| | 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") |
| |
|
| | |
| | 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...) |
| | ) |
| |
|
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | type Marshaler interface { |
| | MarshalJSON() ([]byte, error) |
| | } |
| |
|
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | type MarshalerTo interface { |
| | MarshalJSONTo(*jsontext.Encoder) error |
| |
|
| | |
| | |
| | } |
| |
|
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | type Unmarshaler interface { |
| | UnmarshalJSON([]byte) error |
| | } |
| |
|
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | type UnmarshalerFrom interface { |
| | UnmarshalJSONFrom(*jsontext.Decoder) error |
| |
|
| | |
| | |
| | } |
| |
|
| | func makeMethodArshaler(fncs *arshaler, t reflect.Type) *arshaler { |
| | |
| | |
| | |
| | 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") |
| | } |
| | 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") |
| | } |
| | 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") |
| | } |
| | 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") |
| | } |
| | 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") |
| | } |
| | 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 |
| | } |
| | 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 |
| | } |
| | 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 |
| | } |
| | 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 |
| | } |
| | 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 |
| | } |
| | 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 |
| | } |
| | if !isSyntacticError(err) && !export.IsIOError(err) { |
| | err = newSemanticErrorWithPosition(dec, t, prevDepth, prevLength, err) |
| | } |
| | return err |
| | } |
| | return nil |
| | } |
| | } |
| |
|
| | return fncs |
| | } |
| |
|
| | |
| | |
| | func implementsAny(t reflect.Type, ifaceTypes ...reflect.Type) bool { |
| | for _, ifaceType := range ifaceTypes { |
| | if _, ok := implements(t, ifaceType); ok { |
| | return true |
| | } |
| | } |
| | return false |
| | } |
| |
|
| | |
| | |
| | |
| | |
| | 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 |
| | } |
| | } |
| |
|