aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSergei Skorobogatov <skorobo@rambler.ru>2010-02-22 14:32:40 -0800
committerRuss Cox <rsc@golang.org>2010-02-22 14:32:40 -0800
commit7870672c7f9759b8d7ce578f2476313115342972 (patch)
treee3b79d176cf1069e5406787a095c8c769892410d
parentf5b8124bd9a29841d28e890d198dcb8391b7f86e (diff)
downloadgo-7870672c7f9759b8d7ce578f2476313115342972.tar.gz
go-7870672c7f9759b8d7ce578f2476313115342972.zip
json: fix quoted strings in Marshal
R=rsc CC=golang-dev https://golang.org/cl/217047
-rw-r--r--src/pkg/json/struct.go91
-rw-r--r--src/pkg/json/struct_test.go23
2 files changed, 85 insertions, 29 deletions
diff --git a/src/pkg/json/struct.go b/src/pkg/json/struct.go
index 955ec7c875..3357e04a3c 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, "{")
+ if _, err = fmt.Fprint(w, "{"); err != nil {
+ return
+ }
+
for i := 0; i < len(keys); i++ {
- fmt.Fprintf(w, "%q:", keys[i].(*reflect.StringValue).Get())
+ 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 err
+ 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 f1440c4139..66d6e79c28 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) {