json对象序列化支持包开发
概述
将一个对象写成特定文本格式的字符流,称为序列化。
什么是json
JSON简单的理解就是特殊格式的字符串,被设计用来传输和存储数据,和xml类似,但是在API和前后端分离数据交互更多是使用json,json不仅比XML简单,传输中更节省文本。网站中的ajax、后端api基本上是使用json编码后的数据。
基本规则
- 只有合法的json串才能解析(废话)
key只能是string; map的形式必须是map[string]T,T是Go的基本类型; Channel, complex, function 不能进行编码; 循环数据不支持; 指针会被编码成指针的值,nil是null。
- 只有可导出(exported)的字段才能解析
即首字符大写的字段才能显示在json对象中,解析规则有如下顺序,例如一个key:Foo 1.先找tag是Foo的 2.找字段名是Foo的 3.找FOO或者FoO等
核心功能
参考官方 encoding/json 包 Marshal 函数,将结构数据格式化为 json 字符流
- 导出 func JsonMarshal(v interface{}) ([]byte, error)
- 支持字段的标签(Tag),标签满足 mytag:“你自己的定义”
输出格式
首先需要设定读取后输出的json格式
const (
jsonTag = "json"
jsonStart = "{"
jsonEnd = "}"
arrayStart = "["
arrayEnd = "]"
stringStartEnd = `"`
stringStartEndScaped = ``
is = `:`
comma = ","
null = "null"
empty = " "
booleanTrue = "true"
booleanFalse = "false"
)
读取结果
将从结构体读取的结果存储到marshal结构体中
type marshal struct {
object interface{}
result *bytes.Buffer
tags []string
}
json对象序列化
通过下列函数完成json对象序列化的功能
func (m *marshal) getValue(value reflect.Value) (reflect.Value, reflect.Type, error)
func (m *marshal) do(object reflect.Value) error
func (m *marshal) handleKey(key reflect.Value) error
func (m *marshal) handleValue(object reflect.Value) error
func (m *marshal) handleMarshalJSON(object reflect.Value) (bool, []byte, error)
func (m *marshal) loadTag(typ reflect.StructField) (exists bool, tag string, err error)
func (m *marshal) encodeString(str string) string
JsonMarshal
最后导出JsonMarshal接口
func (m *marshal) execute() ([]byte, error) {
err := m.do(reflect.ValueOf(m.object))
return m.result.Bytes(), err
}
func JsonMarshal(object interface{}, tags ...string) ([]byte, error) {
return newMarshal(object, tags...).execute()
}
单元测试
为了验证JsonMarshal json对象序列化的准确性,我们设置了两个单元测试
func TestMarshal1(t *testing.T) {
expected := `{"name":"joao","age":30,"address":{"number":1.2,"map":{"ola joao":"adeus joao","c":"d"}},"numbers":[1,2,3],"others":{"ola joao":{"number":1.2,"map":{"ola joao":"adeus joao","c":"d"}},"c":{"number":1.2,"map":{"ola joao":"adeus joao","c":"d"}}},"addresses":[{"number":1.2,"map":{"ola joao":"adeus joao","c":"d"}},{"number":1.2,"map":{"ola joao":"adeus joao","c":"d"}}]}`
addr := &address{
Street: "street one",
Number: 1.2,
Map: map[string]string{`"ola" "joao"`: `"adeus" "joao"`, "c": "d"},
}
example := person{
Name: "joao",
Age: 30,
Address: addr,
Numbers: []int{1, 2, 3},
Others: map[string]*address{`"ola" "joao"`: addr, "c": addr},
Addresses: []*address{addr, addr},
}
// with tags "db" and "db.write"
// marshal
bytes, err := JsonMarshal(example, "db", "db.write")
if err != nil {
panic(err)
}
res := string(bytes)
if res != expected {
t.Errorf("expected '%q' but got '%q'", expected, res)
}
}
func TestMarshal2(t *testing.T) {
expected := `{"name":"joao","age":30,"address":{"ports":null,"street":"street one","number":1.2,"map":{"ola joao":"adeus joao","c":"d"}},"numbers":[1,2,3],"others":{"ola joao":{"ports":null,"street":"street one","number":1.2,"map":{"ola joao":"adeus joao","c":"d"}},"c":{"ports":null,"street":"street one","number":1.2,"map":{"ola joao":"adeus joao","c":"d"}}},"addresses":[{"ports":null,"street":"street one","number":1.2,"map":{"ola joao":"adeus joao","c":"d"}},{"ports":null,"street":"street one","number":1.2,"map":{"ola joao":"adeus joao","c":"d"}}]}`
addr := &address{
Street: "street one",
Number: 1.2,
Map: map[string]string{`"ola" "joao"`: `"adeus" "joao"`, "c": "d"},
}
example := person{
Name: "joao",
Age: 30,
Address: addr,
Numbers: []int{1, 2, 3},
Others: map[string]*address{`"ola" "joao"`: addr, "c": addr},
Addresses: []*address{addr, addr},
}
// with tags "db" and "db.read"
// marshal
bytes2, err := JsonMarshal(example, "db", "db.read")
if err != nil {
panic(err)
}
res := string(bytes2)
if res != expected {
t.Errorf("expected '%q' but got '%q'", expected, res)
}
}
运行测试结果如下