41 lines
1.0 KiB
Go
41 lines
1.0 KiB
Go
|
package json
|
||
|
|
||
|
import (
|
||
|
"bytes"
|
||
|
"encoding/json"
|
||
|
"fmt"
|
||
|
)
|
||
|
|
||
|
// Unmarshal is wrapper around json.Unmarshal that returns user-friendly
|
||
|
// errors when there are syntax errors.
|
||
|
func Unmarshal(data []byte, i interface{}) error {
|
||
|
err := json.Unmarshal(data, i)
|
||
|
if err != nil {
|
||
|
syntaxErr, ok := err.(*json.SyntaxError)
|
||
|
if !ok {
|
||
|
return err
|
||
|
}
|
||
|
|
||
|
// We have a syntax error. Extract out the line number and friends.
|
||
|
// https://groups.google.com/forum/#!topic/golang-nuts/fizimmXtVfc
|
||
|
newline := []byte{'\x0a'}
|
||
|
|
||
|
// Calculate the start/end position of the line where the error is
|
||
|
start := bytes.LastIndex(data[:syntaxErr.Offset], newline) + 1
|
||
|
end := len(data)
|
||
|
if idx := bytes.Index(data[start:], newline); idx >= 0 {
|
||
|
end = start + idx
|
||
|
}
|
||
|
|
||
|
// Count the line number we're on plus the offset in the line
|
||
|
line := bytes.Count(data[:start], newline) + 1
|
||
|
pos := int(syntaxErr.Offset) - start - 1
|
||
|
|
||
|
err = fmt.Errorf("Error in line %d, char %d: %s\n%s",
|
||
|
line, pos, syntaxErr, data[start:end])
|
||
|
return err
|
||
|
}
|
||
|
|
||
|
return nil
|
||
|
}
|