From 7870672c7f9759b8d7ce578f2476313115342972 Mon Sep 17 00:00:00 2001 From: Sergei Skorobogatov Date: Mon, 22 Feb 2010 14:32:40 -0800 Subject: [PATCH] json: fix quoted strings in Marshal R=rsc CC=golang-dev https://golang.org/cl/217047 --- src/pkg/json/struct.go | 93 +++++++++++++++++++++++++------------ src/pkg/json/struct_test.go | 23 +++++++++ 2 files changed, 86 insertions(+), 30 deletions(-) diff --git a/src/pkg/json/struct.go b/src/pkg/json/struct.go index 955ec7c8755..3357e04a3c8 100644 --- a/src/pkg/json/struct.go +++ b/src/pkg/json/struct.go @@ -317,76 +317,94 @@ type MarshalError struct { func (e *MarshalError) String() 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++ { - if err := writeValue(w, val.Elem(i)); err != nil { - return err + if err = writeValue(w, val.Elem(i)); err != nil { + return } if i < val.Len()-1 { - fmt.Fprint(w, ",") + if _, err = fmt.Fprint(w, ","); err != nil { + return + } } } - fmt.Fprint(w, "]") - return nil + _, err = fmt.Fprint(w, "]") + 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() if _, ok := key.(*reflect.StringType); !ok { return &MarshalError{val.Type()} } keys := val.Keys() - fmt.Fprint(w, "{") - for i := 0; i < len(keys); i++ { - fmt.Fprintf(w, "%q:", keys[i].(*reflect.StringValue).Get()) + if _, err = fmt.Fprint(w, "{"); err != nil { + return + } - if err := writeValue(w, val.Elem(keys[i])); err != nil { - return err + for i := 0; i < len(keys); i++ { + 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 { - fmt.Fprint(w, ",") + if _, err = fmt.Fprint(w, ","); err != nil { + return + } } } - fmt.Fprint(w, "}") - return nil + _, err = fmt.Fprint(w, "}") + return } -func writeStruct(w io.Writer, val *reflect.StructValue) os.Error { - fmt.Fprint(w, "{") +func writeStruct(w io.Writer, val *reflect.StructValue) (err os.Error) { + if _, err = fmt.Fprint(w, "{"); err != nil { + return + } typ := val.Type().(*reflect.StructType) for i := 0; i < val.NumField(); i++ { fieldValue := val.Field(i) - fmt.Fprintf(w, "%q:", typ.Field(i).Name) - if err := writeValue(w, fieldValue); err != nil { - return err + if _, err = fmt.Fprintf(w, "%s:", Quote(typ.Field(i).Name)); err != nil { + return + } + if err = writeValue(w, fieldValue); err != nil { + return } if i < val.NumField()-1 { - fmt.Fprint(w, ",") + if _, err = fmt.Fprint(w, ","); err != nil { + return + } } } - fmt.Fprint(w, "}") - return nil + _, err = fmt.Fprint(w, "}") + return } func writeValue(w io.Writer, val reflect.Value) (err os.Error) { if val == nil { - fmt.Fprint(w, "null") + _, err = fmt.Fprint(w, "null") return } switch v := val.(type) { case *reflect.StringValue: - fmt.Fprintf(w, "%q", v.Get()) + _, err = fmt.Fprint(w, Quote(v.Get())) case *reflect.ArrayValue: err = writeArrayOrSlice(w, v) case *reflect.SliceValue: @@ -396,27 +414,42 @@ func writeValue(w io.Writer, val reflect.Value) (err os.Error) { case *reflect.StructValue: err = writeStruct(w, v) case *reflect.ChanValue, - *reflect.UnsafePointerValue: + *reflect.UnsafePointerValue, + *reflect.FuncValue: err = &MarshalError{val.Type()} case *reflect.InterfaceValue: if v.IsNil() { - fmt.Fprint(w, "null") + _, err = fmt.Fprint(w, "null") } else { err = writeValue(w, v.Elem()) } case *reflect.PtrValue: if v.IsNil() { - fmt.Fprint(w, "null") + _, err = fmt.Fprint(w, "null") } else { 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: value := val.(reflect.Value) - fmt.Fprint(w, value.Interface()) + _, err = fmt.Fprintf(w, "%#v", value.Interface()) } 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 { return writeValue(w, reflect.NewValue(val)) } diff --git a/src/pkg/json/struct_test.go b/src/pkg/json/struct_test.go index f1440c4139b..66d6e79c288 100644 --- a/src/pkg/json/struct_test.go +++ b/src/pkg/json/struct_test.go @@ -181,6 +181,18 @@ type OneField struct { 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{ // basic string marshalTest{nil, "null"}, @@ -210,6 +222,17 @@ var marshalTests = []marshalTest{ marshalTest{map[string]*MTE{"hi": nil}, `{"hi":null}`}, marshalTest{map[string]interface{}{"hi": 3}, `{"hi":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) {