github.com/galdor/go-ejson@v0.0.0-20231201100034-d335379f26b0/json.go (about) 1 package ejson 2 3 import ( 4 "bytes" 5 "encoding/json" 6 "fmt" 7 "io" 8 "strings" 9 ) 10 11 // It would be nice to have a DecodeStrict() function which would use 12 // (*json.Decoder).DisallowUnknownFields(). Infortunately, the errors produced 13 // this way are not structured and therefore unusable. There is no way out 14 // this whole mess without rewriting an unmarshaller based on 15 // (*json.Decoder).Token(). This would increase memory pressure, but this is 16 // irrelevant for most use cases and would allow much better error reporting. 17 18 func Unmarshal(data []byte, dest interface{}) error { 19 d := json.NewDecoder(bytes.NewReader(data)) 20 return UnmarshalDecoder(d, dest) 21 } 22 23 func UnmarshalDecoder(d *json.Decoder, dest interface{}) error { 24 if err := d.Decode(dest); err != nil { 25 return ConvertUnmarshallingError(err) 26 } 27 28 return Validate(dest) 29 30 } 31 32 func UnmarshalReader(r io.Reader, dest interface{}) error { 33 d := json.NewDecoder(r) 34 return UnmarshalDecoder(d, dest) 35 } 36 37 func ConvertUnmarshallingError(err error) error { 38 switch err2 := err.(type) { 39 case *json.UnmarshalTypeError: 40 var pointer Pointer 41 42 if err2.Field != "" { 43 parts := strings.Split(err2.Field, ".") 44 45 // The Go type system is still completely broken 46 parts2 := make([]interface{}, len(parts)) 47 for i, p := range parts { 48 parts2[i] = p 49 } 50 51 pointer = NewPointer(parts2...) 52 } 53 54 message := fmt.Sprintf("cannot decode %v into value of type %v", 55 err2.Value, err2.Type) 56 57 return ValidationErrors{ 58 &ValidationError{ 59 Pointer: pointer, 60 Code: "invalid_value_type", 61 Message: message, 62 }, 63 } 64 65 default: 66 return err 67 } 68 }