package json
import (
"fmt"
"reflect"
"strconv"
"strings"
"encoding/json/internal"
"encoding/json/jsontext"
jsonv2 "encoding/json/v2"
)
func init() {
internal .TransformMarshalError = transformMarshalError
internal .TransformUnmarshalError = transformUnmarshalError
internal .NewMarshalerError = func (val any , err error , funcName string ) error {
return &MarshalerError {reflect .TypeOf (val ), err , funcName }
}
internal .NewRawNumber = func () any { return new (Number ) }
internal .RawNumberOf = func (b []byte ) any { return Number (b ) }
}
func transformMarshalError(root any , err error ) error {
if err , ok := err .(*jsonv2 .SemanticError ); err != nil {
if err .Err == nil {
return &UnsupportedTypeError {Type : err .GoType }
} else {
errStr := err .Err .Error()
if err .Err == internal .ErrCycle && err .GoType != nil {
errStr += " via " + err .GoType .String ()
}
errStr = strings .TrimPrefix (errStr , "unsupported value: " )
return &UnsupportedValueError {Str : errStr }
}
} else if ok {
return (*UnsupportedValueError )(nil )
}
if err , _ := err .(*MarshalerError ); err != nil {
err .Err = transformSyntacticError (err .Err )
return err
}
return transformSyntacticError (err )
}
func transformUnmarshalError(root any , err error ) error {
if err , ok := err .(*jsonv2 .SemanticError ); err != nil {
if err .Err == internal .ErrNonNilReference {
return &InvalidUnmarshalError {err .GoType }
}
if err .Err == jsonv2 .ErrUnknownName {
return fmt .Errorf ("json: unknown field %q" , err .JSONPointer .LastToken ())
}
var value string
switch err .JSONKind {
case 'n' , '"' , '0' :
value = err .JSONKind .String ()
case 'f' , 't' :
value = "bool"
case '[' , ']' :
value = "array"
case '{' , '}' :
value = "object"
}
if len (err .JSONValue ) > 0 {
isStrconvError := err .Err == strconv .ErrRange || err .Err == strconv .ErrSyntax
isNumericKind := func (t reflect .Type ) bool {
if t == nil {
return false
}
switch t .Kind () {
case reflect .Int , reflect .Int8 , reflect .Int16 , reflect .Int32 , reflect .Int64 ,
reflect .Uint , reflect .Uint8 , reflect .Uint16 , reflect .Uint32 , reflect .Uint64 , reflect .Uintptr ,
reflect .Float32 , reflect .Float64 :
return true
}
return false
}
if isStrconvError && isNumericKind (err .GoType ) {
value = "number"
if err .JSONKind == '"' {
err .JSONValue , _ = jsontext .AppendUnquote (nil , err .JSONValue )
}
err .Err = nil
}
value += " " + string (err .JSONValue )
}
var rootName string
if t := reflect .TypeOf (root ); t != nil && err .JSONPointer != "" {
if t .Kind () == reflect .Pointer {
t = t .Elem ()
}
rootName = t .Name ()
}
fieldPath := string (err .JSONPointer )
fieldPath = strings .TrimPrefix (fieldPath , "/" )
fieldPath = strings .ReplaceAll (fieldPath , "/" , "." )
return &UnmarshalTypeError {
Value : value ,
Type : err .GoType ,
Offset : err .ByteOffset ,
Struct : rootName ,
Field : fieldPath ,
Err : transformSyntacticError (err .Err ),
}
} else if ok {
return (*UnmarshalTypeError )(nil )
}
return transformSyntacticError (err )
}
The pages are generated with Golds v0.7.7-preview . (GOOS=linux GOARCH=amd64)
Golds is a Go 101 project developed by Tapir Liu .
PR and bug reports are welcome and can be submitted to the issue list .
Please follow @zigo_101 (reachable from the left QR code) to get the latest news of Golds .