package json
import (
)
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 ( *arshaler, reflect.Type) *arshaler {
if .Kind() == reflect.Pointer || .Kind() == reflect.Interface {
return
}
if , := implements(, textMarshalerType); {
.nonDefault = true
:= .marshal
.marshal = func( *jsontext.Encoder, addressableValue, *jsonopts.Struct) error {
if .Flags.Get(jsonflags.CallMethodsWithLegacySemantics) &&
(( && .forcedAddr) ||
(export.Encoder().Tokens.Last.NeedObjectName()) && .Kind() == reflect.String) {
return (, , )
}
, := reflect.TypeAssert[encoding.TextMarshaler](.Addr())
if := export.Encoder().AppendRaw('"', false, func( []byte) ([]byte, error) {
, := .MarshalText()
return append(, ...),
}); != nil {
= wrapErrUnsupported(, "MarshalText method")
if .Flags.Get(jsonflags.ReportErrorsWithLegacySemantics) {
return internal.NewMarshalerError(.Addr().Interface(), , "MarshalText")
}
if !isSemanticError() && !export.IsIOError() {
= newMarshalErrorBefore(, , )
}
return
}
return nil
}
}
if , := implements(, textAppenderType); {
.nonDefault = true
:= .marshal
.marshal = func( *jsontext.Encoder, addressableValue, *jsonopts.Struct) ( error) {
if .Flags.Get(jsonflags.CallMethodsWithLegacySemantics) &&
(( && .forcedAddr) ||
(export.Encoder().Tokens.Last.NeedObjectName()) && .Kind() == reflect.String) {
return (, , )
}
, := reflect.TypeAssert[encoding.TextAppender](.Addr())
if := export.Encoder().AppendRaw('"', false, .AppendText); != nil {
= wrapErrUnsupported(, "AppendText method")
if .Flags.Get(jsonflags.ReportErrorsWithLegacySemantics) {
return internal.NewMarshalerError(.Addr().Interface(), , "AppendText")
}
if !isSemanticError() && !export.IsIOError() {
= newMarshalErrorBefore(, , )
}
return
}
return nil
}
}
if , := implements(, jsonMarshalerType); {
.nonDefault = true
:= .marshal
.marshal = func( *jsontext.Encoder, addressableValue, *jsonopts.Struct) error {
if .Flags.Get(jsonflags.CallMethodsWithLegacySemantics) &&
(( && .forcedAddr) || export.Encoder().Tokens.Last.NeedObjectName()) {
return (, , )
}
, := reflect.TypeAssert[Marshaler](.Addr())
, := .MarshalJSON()
if != nil {
= wrapErrUnsupported(, "MarshalJSON method")
if .Flags.Get(jsonflags.ReportErrorsWithLegacySemantics) {
return internal.NewMarshalerError(.Addr().Interface(), , "MarshalJSON")
}
= newMarshalErrorBefore(, , )
return collapseSemanticErrors()
}
if := .WriteValue(); != nil {
if .Flags.Get(jsonflags.ReportErrorsWithLegacySemantics) {
return internal.NewMarshalerError(.Addr().Interface(), , "MarshalJSON")
}
if isSyntacticError() {
= newMarshalErrorBefore(, , )
}
return
}
return nil
}
}
if , := implements(, jsonMarshalerToType); {
.nonDefault = true
:= .marshal
.marshal = func( *jsontext.Encoder, addressableValue, *jsonopts.Struct) error {
if .Flags.Get(jsonflags.CallMethodsWithLegacySemantics) &&
(( && .forcedAddr) || export.Encoder().Tokens.Last.NeedObjectName()) {
return (, , )
}
:= export.Encoder()
, := .Tokens.DepthLength()
.Flags.Set(jsonflags.WithinArshalCall | 1)
, := reflect.TypeAssert[MarshalerTo](.Addr())
:= .MarshalJSONTo()
.Flags.Set(jsonflags.WithinArshalCall | 0)
, := .Tokens.DepthLength()
if ( != || +1 != ) && == nil {
= errNonSingularValue
}
if != nil {
if errors.Is(, errors.ErrUnsupported) {
if == && == {
return (, , )
}
= errUnsupportedMutation
}
if .Flags.Get(jsonflags.ReportErrorsWithLegacySemantics) {
return internal.NewMarshalerError(.Addr().Interface(), , "MarshalJSONTo")
}
if !export.IsIOError() {
= newSemanticErrorWithPosition(, , , , )
}
return
}
return nil
}
}
if , := implements(, textUnmarshalerType); {
.nonDefault = true
.unmarshal = func( *jsontext.Decoder, addressableValue, *jsonopts.Struct) error {
:= export.Decoder()
var jsonwire.ValueFlags
, := .ReadValue(&)
if != nil {
return
}
if .Kind() == 'n' {
if !.Flags.Get(jsonflags.MergeWithLegacySemantics) {
.SetZero()
}
return nil
}
if .Kind() != '"' {
return newUnmarshalErrorAfter(, , errNonStringValue)
}
:= jsonwire.UnquoteMayCopy(, .IsVerbatim())
, := reflect.TypeAssert[encoding.TextUnmarshaler](.Addr())
if := .UnmarshalText(); != nil {
= wrapErrUnsupported(, "UnmarshalText method")
if .Flags.Get(jsonflags.ReportErrorsWithLegacySemantics) {
return
}
if !isSemanticError() && !isSyntacticError() && !export.IsIOError() {
= newUnmarshalErrorAfter(, , )
}
return
}
return nil
}
}
if , := implements(, jsonUnmarshalerType); {
.nonDefault = true
:= .unmarshal
.unmarshal = func( *jsontext.Decoder, addressableValue, *jsonopts.Struct) error {
if .Flags.Get(jsonflags.CallMethodsWithLegacySemantics) &&
export.Decoder().Tokens.Last.NeedObjectName() {
return (, , )
}
, := .ReadValue()
if != nil {
return
}
, := reflect.TypeAssert[Unmarshaler](.Addr())
if := .UnmarshalJSON(); != nil {
= wrapErrUnsupported(, "UnmarshalJSON method")
if .Flags.Get(jsonflags.ReportErrorsWithLegacySemantics) {
return
}
= newUnmarshalErrorAfter(, , )
return collapseSemanticErrors()
}
return nil
}
}
if , := implements(, jsonUnmarshalerFromType); {
.nonDefault = true
:= .unmarshal
.unmarshal = func( *jsontext.Decoder, addressableValue, *jsonopts.Struct) error {
if .Flags.Get(jsonflags.CallMethodsWithLegacySemantics) &&
export.Decoder().Tokens.Last.NeedObjectName() {
return (, , )
}
:= export.Decoder()
, := .Tokens.DepthLength()
if == 1 && .AtEOF() {
return io.EOF
}
.Flags.Set(jsonflags.WithinArshalCall | 1)
, := reflect.TypeAssert[UnmarshalerFrom](.Addr())
:= .UnmarshalJSONFrom()
.Flags.Set(jsonflags.WithinArshalCall | 0)
, := .Tokens.DepthLength()
if ( != || +1 != ) && == nil {
= errNonSingularValue
}
if != nil {
if errors.Is(, errors.ErrUnsupported) {
if == && == {
return (, , )
}
= errUnsupportedMutation
}
if .Flags.Get(jsonflags.ReportErrorsWithLegacySemantics) {
if := .SkipUntil(, +1); != nil {
return
}
return
}
if !isSyntacticError() && !export.IsIOError() {
= newSemanticErrorWithPosition(, , , , )
}
return
}
return nil
}
}
return
}
func ( reflect.Type, ...reflect.Type) bool {
for , := range {
if , := implements(, ); {
return true
}
}
return false
}
func (, reflect.Type) (, bool) {
switch {
case .Implements():
return false, true
case reflect.PointerTo().Implements():
return true, true
default:
return false, false
}
}