1
0
mirror of https://github.com/golang/go synced 2024-11-25 15:17:58 -07:00

json: fix quoted strings in Marshal

R=rsc
CC=golang-dev
https://golang.org/cl/217047
This commit is contained in:
Sergei Skorobogatov 2010-02-22 14:32:40 -08:00 committed by Russ Cox
parent f5b8124bd9
commit 7870672c7f
2 changed files with 86 additions and 30 deletions

View File

@ -317,76 +317,94 @@ type MarshalError struct {
func (e *MarshalError) String() string { func (e *MarshalError) String() string {
return "json cannot encode value of type " + e.T.String() return "json cannot encode value of type " + e.T.String()
} }
func writeArrayOrSlice(w io.Writer, val reflect.ArrayOrSliceValue) os.Error {
fmt.Fprint(w, "[") func writeArrayOrSlice(w io.Writer, val reflect.ArrayOrSliceValue) (err os.Error) {
if _, err = fmt.Fprint(w, "["); err != nil {
return
}
for i := 0; i < val.Len(); i++ { for i := 0; i < val.Len(); i++ {
if err := writeValue(w, val.Elem(i)); err != nil { if err = writeValue(w, val.Elem(i)); err != nil {
return err return
} }
if i < val.Len()-1 { if i < val.Len()-1 {
fmt.Fprint(w, ",") if _, err = fmt.Fprint(w, ","); err != nil {
return
}
} }
} }
fmt.Fprint(w, "]") _, err = fmt.Fprint(w, "]")
return nil return
} }
func writeMap(w io.Writer, val *reflect.MapValue) os.Error { func writeMap(w io.Writer, val *reflect.MapValue) (err os.Error) {
key := val.Type().(*reflect.MapType).Key() key := val.Type().(*reflect.MapType).Key()
if _, ok := key.(*reflect.StringType); !ok { if _, ok := key.(*reflect.StringType); !ok {
return &MarshalError{val.Type()} return &MarshalError{val.Type()}
} }
keys := val.Keys() keys := val.Keys()
fmt.Fprint(w, "{") if _, err = fmt.Fprint(w, "{"); err != nil {
for i := 0; i < len(keys); i++ { return
fmt.Fprintf(w, "%q:", keys[i].(*reflect.StringValue).Get()) }
if err := writeValue(w, val.Elem(keys[i])); err != nil { for i := 0; i < len(keys); i++ {
return err if _, err = fmt.Fprintf(w, "%s:", Quote(keys[i].(*reflect.StringValue).Get())); err != nil {
return
}
if err = writeValue(w, val.Elem(keys[i])); err != nil {
return
} }
if i < len(keys)-1 { if i < len(keys)-1 {
fmt.Fprint(w, ",") if _, err = fmt.Fprint(w, ","); err != nil {
return
}
} }
} }
fmt.Fprint(w, "}") _, err = fmt.Fprint(w, "}")
return nil return
} }
func writeStruct(w io.Writer, val *reflect.StructValue) os.Error { func writeStruct(w io.Writer, val *reflect.StructValue) (err os.Error) {
fmt.Fprint(w, "{") if _, err = fmt.Fprint(w, "{"); err != nil {
return
}
typ := val.Type().(*reflect.StructType) typ := val.Type().(*reflect.StructType)
for i := 0; i < val.NumField(); i++ { for i := 0; i < val.NumField(); i++ {
fieldValue := val.Field(i) fieldValue := val.Field(i)
fmt.Fprintf(w, "%q:", typ.Field(i).Name) if _, err = fmt.Fprintf(w, "%s:", Quote(typ.Field(i).Name)); err != nil {
if err := writeValue(w, fieldValue); err != nil { return
return err }
if err = writeValue(w, fieldValue); err != nil {
return
} }
if i < val.NumField()-1 { if i < val.NumField()-1 {
fmt.Fprint(w, ",") if _, err = fmt.Fprint(w, ","); err != nil {
return
}
} }
} }
fmt.Fprint(w, "}") _, err = fmt.Fprint(w, "}")
return nil return
} }
func writeValue(w io.Writer, val reflect.Value) (err os.Error) { func writeValue(w io.Writer, val reflect.Value) (err os.Error) {
if val == nil { if val == nil {
fmt.Fprint(w, "null") _, err = fmt.Fprint(w, "null")
return return
} }
switch v := val.(type) { switch v := val.(type) {
case *reflect.StringValue: case *reflect.StringValue:
fmt.Fprintf(w, "%q", v.Get()) _, err = fmt.Fprint(w, Quote(v.Get()))
case *reflect.ArrayValue: case *reflect.ArrayValue:
err = writeArrayOrSlice(w, v) err = writeArrayOrSlice(w, v)
case *reflect.SliceValue: case *reflect.SliceValue:
@ -396,27 +414,42 @@ func writeValue(w io.Writer, val reflect.Value) (err os.Error) {
case *reflect.StructValue: case *reflect.StructValue:
err = writeStruct(w, v) err = writeStruct(w, v)
case *reflect.ChanValue, case *reflect.ChanValue,
*reflect.UnsafePointerValue: *reflect.UnsafePointerValue,
*reflect.FuncValue:
err = &MarshalError{val.Type()} err = &MarshalError{val.Type()}
case *reflect.InterfaceValue: case *reflect.InterfaceValue:
if v.IsNil() { if v.IsNil() {
fmt.Fprint(w, "null") _, err = fmt.Fprint(w, "null")
} else { } else {
err = writeValue(w, v.Elem()) err = writeValue(w, v.Elem())
} }
case *reflect.PtrValue: case *reflect.PtrValue:
if v.IsNil() { if v.IsNil() {
fmt.Fprint(w, "null") _, err = fmt.Fprint(w, "null")
} else { } else {
err = writeValue(w, v.Elem()) err = writeValue(w, v.Elem())
} }
case *reflect.UintptrValue:
_, err = fmt.Fprintf(w, "%d", v.Get())
case *reflect.Uint64Value:
_, err = fmt.Fprintf(w, "%d", v.Get())
case *reflect.Uint32Value:
_, err = fmt.Fprintf(w, "%d", v.Get())
case *reflect.Uint16Value:
_, err = fmt.Fprintf(w, "%d", v.Get())
case *reflect.Uint8Value:
_, err = fmt.Fprintf(w, "%d", v.Get())
default: default:
value := val.(reflect.Value) value := val.(reflect.Value)
fmt.Fprint(w, value.Interface()) _, err = fmt.Fprintf(w, "%#v", value.Interface())
} }
return return
} }
// Marshal writes the JSON encoding of val to w.
//
// Due to limitations in JSON, val cannot include cyclic data
// structures, channels, functions, or maps.
func Marshal(w io.Writer, val interface{}) os.Error { func Marshal(w io.Writer, val interface{}) os.Error {
return writeValue(w, reflect.NewValue(val)) return writeValue(w, reflect.NewValue(val))
} }

View File

@ -181,6 +181,18 @@ type OneField struct {
a int a int
} }
type ScalarWithString int
const (
AA ScalarWithString = iota
BB
CC
)
var scalarStrings = []string{"AA", "BB", "CC"}
func (x ScalarWithString) String() string { return scalarStrings[x] }
var marshalTests = []marshalTest{ var marshalTests = []marshalTest{
// basic string // basic string
marshalTest{nil, "null"}, marshalTest{nil, "null"},
@ -210,6 +222,17 @@ var marshalTests = []marshalTest{
marshalTest{map[string]*MTE{"hi": nil}, `{"hi":null}`}, marshalTest{map[string]*MTE{"hi": nil}, `{"hi":null}`},
marshalTest{map[string]interface{}{"hi": 3}, `{"hi":3}`}, marshalTest{map[string]interface{}{"hi": 3}, `{"hi":3}`},
marshalTest{&OneField{3}, `{"a":3}`}, marshalTest{&OneField{3}, `{"a":3}`},
marshalTest{"\x05\x06", `"\u0005\u0006"`},
marshalTest{uintptr(50000), "50000"},
marshalTest{uint64(50000), "50000"},
marshalTest{uint32(50000), "50000"},
marshalTest{uint16(50000), "50000"},
marshalTest{uint8(50), "50"},
marshalTest{int64(50000), "50000"},
marshalTest{int32(50000), "50000"},
marshalTest{int16(10000), "10000"},
marshalTest{int8(50), "50"},
marshalTest{BB, "1"},
} }
func TestMarshal(t *testing.T) { func TestMarshal(t *testing.T) {