Skip to content

Commit

Permalink
first init
Browse files Browse the repository at this point in the history
  • Loading branch information
lichao115 committed Apr 1, 2017
1 parent 18a224c commit 2121b5e
Show file tree
Hide file tree
Showing 2 changed files with 143 additions and 0 deletions.
118 changes: 118 additions & 0 deletions jsonfield.go
Original file line number Diff line number Diff line change
@@ -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()
)
25 changes: 25 additions & 0 deletions jsonfield_test.go
Original file line number Diff line number Diff line change
@@ -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
}

0 comments on commit 2121b5e

Please sign in to comment.