From 2121b5e2274a2bd66eafc581828487f5586bcbc8 Mon Sep 17 00:00:00 2001 From: lichao115 Date: Sat, 1 Apr 2017 15:06:26 +0800 Subject: [PATCH] first init --- jsonfield.go | 118 ++++++++++++++++++++++++++++++++++++++++++++++ jsonfield_test.go | 25 ++++++++++ 2 files changed, 143 insertions(+) create mode 100644 jsonfield.go create mode 100644 jsonfield_test.go diff --git a/jsonfield.go b/jsonfield.go new file mode 100644 index 0000000..c6b3beb --- /dev/null +++ b/jsonfield.go @@ -0,0 +1,118 @@ +package jsonfield + +import ( + "bytes" + "encoding/json" + "fmt" + "reflect" + "strconv" + + fflib "github.com/pquerna/ffjson/fflib/v1" +) + +func Marshal(v interface{}, fields ...string) ([]byte, error) { + if len(fields) == 0 { + return json.Marshal(v) + } else { + return MarshalFields(v, fields) + } +} + +func MarshalFields(c interface{}, fields []string) ([]byte, error) { + buf := bytes.NewBuffer(nil) + + _, v := Reflect(c) + + buf.WriteString("{") + for i, field := range fields { + vv := v.FieldByName(field) + if vv.Kind() != reflect.Invalid { + buf.WriteString(`"` + field + `":`) + + var err error + switch vv.Kind() { + case reflect.Bool: + zzz := strconv.AppendBool(nil, vv.Bool()) + _, err = buf.Write(zzz) + case reflect.Int8, reflect.Int, reflect.Int16, reflect.Int32, reflect.Int64: + i := vv.Int() + fflib.FormatBits2(buf, uint64(i), 10, i < 0) + case reflect.Uint, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uint8: + i := vv.Uint() + fflib.FormatBits2(buf, uint64(i), 10, i < 0) + case reflect.Float32, reflect.Float64: + zzz := strconv.AppendFloat(nil, vv.Float(), 'g', -1, 64) + _, err = buf.Write(zzz) + case reflect.String: + _, err = buf.WriteString(vv.String()) + case reflect.Slice, reflect.Map, reflect.Array: + if vv.IsNil() { + buf.WriteString("null") + } else { + _, err = buf.WriteString(fmt.Sprintf(`"%+v"`, vv.Interface())) + } + case reflect.Struct: + tt := reflect.TypeOf(vv.Interface()) + if tt.Implements(marshalerType) { + m := vv.Interface().(json.Marshaler) + b, err := m.MarshalJSON() + if err != nil { + return nil, err + } else { + b, err := json.Marshal(vv.Interface()) + if err != nil { + return nil, err + } + _, err = buf.Write(b) + } + _, err = buf.Write(b) + } + case reflect.Ptr: + tt := reflect.TypeOf(vv.Interface()).Elem() + if tt.Implements(marshalerType) { + m := vv.Interface().(json.Marshaler) + b, err := m.MarshalJSON() + if err != nil { + return nil, err + } + _, err = buf.Write(b) + } else { + b, err := json.Marshal(vv.Interface()) + if err != nil { + return nil, err + } + _, err = buf.Write(b) + } + default: + _, err = buf.WriteString(vv.String()) + } + + if err != nil { + return nil, err + } + } + + if i != len(fields)-1 { + buf.WriteString(",") + } + } + + buf.WriteString("}") + + return buf.Bytes(), nil +} + +func Reflect(c interface{}) (reflect.Type, reflect.Value) { + t := reflect.TypeOf(c) + v := reflect.ValueOf(c) + if t.Kind() == reflect.Ptr { + t = t.Elem() + v = reflect.Indirect(v) + } + + return t, v +} + +var ( + marshalerType = reflect.TypeOf(new(json.Marshaler)).Elem() +) diff --git a/jsonfield_test.go b/jsonfield_test.go new file mode 100644 index 0000000..47eaaf5 --- /dev/null +++ b/jsonfield_test.go @@ -0,0 +1,25 @@ +package jsonfield + +import "testing" + +func TestJsonTest(t *testing.T) { + jj := new(A) + jj.A, jj.B = 111, 222 + + if byts, err := Marshal(jj); err != nil || string(byts) != `{"A":111,"B":222}` { + t.Error(string(byts), err) + } + + if byts, err := Marshal(jj, "A"); err != nil || string(byts) != `{"A":111}` { + t.Error(string(byts), err) + } + + if byts, err := Marshal(jj, "B"); err != nil || string(byts) != `{"B":222}` { + t.Error(string(byts), err) + } +} + +type A struct { + A int + B int +}