json: better error messages when the ,string option is misused

Fixes #2331

R=golang-dev, rsc
CC=golang-dev
https://golang.org/cl/5544045
This commit is contained in:
Brad Fitzpatrick 2012-01-12 14:40:29 -08:00
parent c624fa691d
commit b37de7387a
16 changed files with 431 additions and 413 deletions

View file

@ -10,6 +10,7 @@ package json
import (
"encoding/base64"
"errors"
"fmt"
"reflect"
"runtime"
"strconv"
@ -538,7 +539,7 @@ func (d *decodeState) object(v reflect.Value) {
// Read value.
if destring {
d.value(reflect.ValueOf(&d.tempstr))
d.literalStore([]byte(d.tempstr), subv)
d.literalStore([]byte(d.tempstr), subv, true)
} else {
d.value(subv)
}
@ -571,11 +572,15 @@ func (d *decodeState) literal(v reflect.Value) {
d.off--
d.scan.undo(op)
d.literalStore(d.data[start:d.off], v)
d.literalStore(d.data[start:d.off], v, false)
}
// literalStore decodes a literal stored in item into v.
func (d *decodeState) literalStore(item []byte, v reflect.Value) {
//
// fromQuoted indicates whether this literal came from unwrapping a
// string from the ",string" struct tag option. this is used only to
// produce more helpful error messages.
func (d *decodeState) literalStore(item []byte, v reflect.Value, fromQuoted bool) {
// Check for unmarshaler.
wantptr := item[0] == 'n' // null
unmarshaler, pv := d.indirect(v, wantptr)
@ -601,7 +606,11 @@ func (d *decodeState) literalStore(item []byte, v reflect.Value) {
value := c == 't'
switch v.Kind() {
default:
d.saveError(&UnmarshalTypeError{"bool", v.Type()})
if fromQuoted {
d.saveError(fmt.Errorf("json: invalid use of ,string struct tag, trying to unmarshal %q into %v", item, v.Type()))
} else {
d.saveError(&UnmarshalTypeError{"bool", v.Type()})
}
case reflect.Bool:
v.SetBool(value)
case reflect.Interface:
@ -611,7 +620,11 @@ func (d *decodeState) literalStore(item []byte, v reflect.Value) {
case '"': // string
s, ok := unquoteBytes(item)
if !ok {
d.error(errPhase)
if fromQuoted {
d.error(fmt.Errorf("json: invalid use of ,string struct tag, trying to unmarshal %q into %v", item, v.Type()))
} else {
d.error(errPhase)
}
}
switch v.Kind() {
default:
@ -636,12 +649,20 @@ func (d *decodeState) literalStore(item []byte, v reflect.Value) {
default: // number
if c != '-' && (c < '0' || c > '9') {
d.error(errPhase)
if fromQuoted {
d.error(fmt.Errorf("json: invalid use of ,string struct tag, trying to unmarshal %q into %v", item, v.Type()))
} else {
d.error(errPhase)
}
}
s := string(item)
switch v.Kind() {
default:
d.error(&UnmarshalTypeError{"number", v.Type()})
if fromQuoted {
d.error(fmt.Errorf("json: invalid use of ,string struct tag, trying to unmarshal %q into %v", item, v.Type()))
} else {
d.error(&UnmarshalTypeError{"number", v.Type()})
}
case reflect.Interface:
n, err := strconv.ParseFloat(s, 64)
if err != nil {