1
0
mirror of https://github.com/golang/go synced 2024-11-22 09:44:40 -07:00

Add json.Marshal to json package

R=rsc
CC=golang-dev
https://golang.org/cl/157068
This commit is contained in:
Michael Hoisie 2009-11-19 20:45:03 -08:00 committed by Russ Cox
parent 121bb921fb
commit ce88bfa585
2 changed files with 143 additions and 0 deletions

View File

@ -8,6 +8,9 @@
package json package json
import ( import (
"fmt";
"io";
"os";
"reflect"; "reflect";
"strings"; "strings";
) )
@ -306,3 +309,97 @@ func Unmarshal(s string, val interface{}) (ok bool, errtok string) {
} }
return true, ""; 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))
}

View File

@ -5,6 +5,7 @@
package json package json
import ( import (
"bytes";
"reflect"; "reflect";
"strconv"; "strconv";
"testing"; "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)
}
}
}