mirror of
https://github.com/golang/go
synced 2024-11-25 09:07:58 -07:00
Add json.Marshal to json package
R=rsc CC=golang-dev https://golang.org/cl/157068
This commit is contained in:
parent
121bb921fb
commit
ce88bfa585
@ -8,6 +8,9 @@
|
||||
package json
|
||||
|
||||
import (
|
||||
"fmt";
|
||||
"io";
|
||||
"os";
|
||||
"reflect";
|
||||
"strings";
|
||||
)
|
||||
@ -306,3 +309,97 @@ func Unmarshal(s string, val interface{}) (ok bool, errtok string) {
|
||||
}
|
||||
return true, "";
|
||||
}
|
||||
|
||||
type MarshalError struct {
|
||||
T reflect.Type;
|
||||
}
|
||||
|
||||
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, "[");
|
||||
|
||||
for i := 0; i < val.Len(); i++ {
|
||||
if err := writeValue(w, val.Elem(i)); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if i < val.Len()-1 {
|
||||
fmt.Fprint(w, ",")
|
||||
}
|
||||
}
|
||||
|
||||
fmt.Fprint(w, "]");
|
||||
return nil;
|
||||
}
|
||||
|
||||
func writeMap(w io.Writer, val *reflect.MapValue) 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 := writeValue(w, val.Elem(keys[i])); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if i < len(keys)-1 {
|
||||
fmt.Fprint(w, ",")
|
||||
}
|
||||
}
|
||||
|
||||
fmt.Fprint(w, "}");
|
||||
return nil;
|
||||
}
|
||||
|
||||
func writeStruct(w io.Writer, val *reflect.StructValue) os.Error {
|
||||
fmt.Fprint(w, "{");
|
||||
|
||||
typ := val.Type().(*reflect.StructType);
|
||||
|
||||
for i := 0; i < val.NumField(); i++ {
|
||||
fieldValue := val.Field(i);
|
||||
fmt.Fprintf(w, "%q:", typ.Field(i).Name);
|
||||
writeValue(w, fieldValue);
|
||||
if i < val.NumField()-1 {
|
||||
fmt.Fprint(w, ",")
|
||||
}
|
||||
}
|
||||
|
||||
fmt.Fprint(w, "}");
|
||||
return nil;
|
||||
}
|
||||
|
||||
func writeValue(w io.Writer, val reflect.Value) (err os.Error) {
|
||||
switch v := val.(type) {
|
||||
case *reflect.StringValue:
|
||||
fmt.Fprintf(w, "%q", v.Get())
|
||||
case *reflect.ArrayValue:
|
||||
err = writeArrayOrSlice(w, v)
|
||||
case *reflect.SliceValue:
|
||||
err = writeArrayOrSlice(w, v)
|
||||
case *reflect.MapValue:
|
||||
err = writeMap(w, v)
|
||||
case *reflect.StructValue:
|
||||
err = writeStruct(w, v)
|
||||
case *reflect.ChanValue,
|
||||
*reflect.InterfaceValue,
|
||||
*reflect.PtrValue,
|
||||
*reflect.UnsafePointerValue:
|
||||
return &MarshalError{val.Type()}
|
||||
default:
|
||||
value := val.(reflect.Value);
|
||||
fmt.Fprint(w, value.Interface());
|
||||
}
|
||||
return nil;
|
||||
}
|
||||
|
||||
func Marshal(w io.Writer, val interface{}) os.Error {
|
||||
return writeValue(w, reflect.NewValue(val))
|
||||
}
|
||||
|
@ -5,6 +5,7 @@
|
||||
package json
|
||||
|
||||
import (
|
||||
"bytes";
|
||||
"reflect";
|
||||
"strconv";
|
||||
"testing";
|
||||
@ -157,3 +158,48 @@ func TestIssue114(t *testing.T) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
type marshalTest struct {
|
||||
val interface{};
|
||||
out string;
|
||||
}
|
||||
|
||||
var marshalTests = []marshalTest{
|
||||
// basic string
|
||||
marshalTest{true, "true"},
|
||||
marshalTest{false, "false"},
|
||||
marshalTest{123, "123"},
|
||||
marshalTest{0.1, "0.1"},
|
||||
marshalTest{1e-10, "1e-10"},
|
||||
marshalTest{"teststring", `"teststring"`},
|
||||
marshalTest{[4]int{1, 2, 3, 4}, "[1,2,3,4]"},
|
||||
marshalTest{[]int{1, 2, 3, 4}, "[1,2,3,4]"},
|
||||
marshalTest{[][]int{[]int{1, 2}, []int{3, 4}}, "[[1,2],[3,4]]"},
|
||||
marshalTest{map[string]string{"one": "one"}, `{"one":"one"}`},
|
||||
marshalTest{map[string]int{"one": 1}, `{"one":1}`},
|
||||
marshalTest{struct{}{}, "{}"},
|
||||
marshalTest{struct{ a int }{1}, `{"a":1}`},
|
||||
marshalTest{struct {
|
||||
a int;
|
||||
b string;
|
||||
}{1, "hello"},
|
||||
`{"a":1,"b":"hello"}`,
|
||||
},
|
||||
marshalTest{map[string][]int{"3": []int{1, 2, 3}}, `{"3":[1,2,3]}`},
|
||||
}
|
||||
|
||||
func TestJsonMarshal(t *testing.T) {
|
||||
for _, tt := range marshalTests {
|
||||
var buf bytes.Buffer;
|
||||
|
||||
err := Marshal(&buf, tt.val);
|
||||
if err != nil {
|
||||
t.Errorf("Error converting %s to JSON: \n", err.String())
|
||||
}
|
||||
|
||||
s := buf.String();
|
||||
if s != tt.out {
|
||||
t.Errorf("Error converting to JSON. Expected: %q Actual %q\n", tt.out, s)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user