一、概述
nGoJsons是一个集成方便应用层使用的Json库,是一个内部有内嵌的自研的Json库。
让应用层有更多的选择和方便使用。即有浅层的封装,也有自我特色的自研的Json库。
二、特点
- 兼容官方 sdk的 Json接口
- 获取部分Json的解析数据
三、集成的开源库
3.1、序列化和反序列化支持的开源库
- Stdlib
- go-json
- json-iterator
- sonic
3.2、Parse - Get 支持的开源库
- fastjson
- json-iterator
- sonic
- SimpleJson
- jsonparser
- ngeyjson
其中 ngeyjson是我自研的json库,目前只开放了Get接口部分。
四、统一的接口
4.1、序列化/反序列化的接口
type Decoder interface {
Decode(val interface{}) error
Buffered() io.Reader
DisallowUnknownFields()
More() bool
UseNumber()
}
type Encoder interface {
Encode(val interface{}) error
SetEscapeHTML(on bool)
SetIndent(prefix, indent string)
}
HTMLEscape
Marshal
MarshalIndent
Indent
Valid
Unmarshal
NewDecoder
NewEncoder
4.2、Parse - Get 接口
type IJsonParseRet interface {
Get(key string) IJsonParseRet
Array() ([]IJsonParseRet, error)
Bool() (bool, error)
String() (string, error)
Float64() (float64, error)
Int() (int, error)
Uint() (uint, error)
Int64() (int64, error)
Uint64() (uint64, error)
}
五、用法
5.1、Marshal/Unmarshal 等
func testMarshal() {
var s = struct {
Name string
Age int
}{
"json",
30,
}
fmt.Println("----- Marshal Default Test -------")
retbytes, err := nGoJsons.Marshal(&s)
if err != nil {
fmt.Println(err)
return
}
fmt.Println(string(retbytes))
fmt.Println("----- Marshal StdlibJsonFrame Test -------")
retbytes, err = nGoJsons.Marshal(&s, nGoJsons.SetJsonFrame(nGoJsons.StdlibJsonFrame))
if err != nil {
fmt.Println(err)
return
}
fmt.Println(string(retbytes))
fmt.Println("----- Marshal GoJsonFrame Test -------")
retbytes, err = nGoJsons.Marshal(&s, nGoJsons.SetJsonFrame(nGoJsons.GoJsonFrame))
if err != nil {
fmt.Println(err)
return
}
fmt.Println(string(retbytes))
fmt.Println("----- Marshal SonicJsonFrame Test -------")
retbytes, err = nGoJsons.Marshal(&s, nGoJsons.SetJsonFrame(nGoJsons.SonicJsonFrame))
if err != nil {
fmt.Println(err)
return
}
fmt.Println(string(retbytes))
fmt.Println("----- Marshal JsonIterJsonFrame Test -------")
retbytes, err = nGoJsons.Marshal(&s, nGoJsons.SetJsonFrame(nGoJsons.JsonIterJsonFrame))
if err != nil {
fmt.Println(err)
return
}
fmt.Println(string(retbytes))
}
5.2、Get 用法
func TestJson1(t *testing.T) {
s := []byte(`{"name":{"first":"Janet","last":"Prichard"},"age":47}`)
var fn = func(v ijsoner.IJsonParseRet) {
defer func() { JsonParse.ReleaseCache(v) }()
vstr, err := v.String()
if err != nil {
t.Fatal(err)
}
t.Log(vstr)
vstr, err = v.Get("name").String()
if err != nil {
t.Fatal(err)
}
t.Log(vstr)
str, err := v.Get("name").Get("first").String()
if err != nil {
t.Fatal(err)
}
t.Log(str)
str, err = v.Get("name").Get("last").String()
if err != nil {
t.Fatal(err)
}
t.Log(str)
age, err := v.Get("age").Int()
if err != nil {
t.Fatal(err)
}
t.Log(age)
}
t.Run("testDefaultParse", func(t *testing.T) {
v, err := JsonParse.Parse(s)
if err != nil {
t.Fatalf("unexpected error: %s", err)
}
fn(v)
})
t.Run("testSimpleJsonParse", func(t *testing.T) {
v, err := JsonParse.Parse(s, JsonParse.SetParseFrame(JsonParse.SimpleJsonFrame))
if err != nil {
t.Fatalf("unexpected error: %s", err)
}
fn(v)
})
t.Run("testFastJsonParse", func(t *testing.T) {
v, err := JsonParse.Parse(s, JsonParse.SetParseFrame(JsonParse.FastJsonFrame))
if err != nil {
t.Fatalf("unexpected error: %s", err)
}
fn(v)
})
t.Run("testGeyJsonParse", func(t *testing.T) {
v, err := JsonParse.Parse(s, JsonParse.SetParseFrame(JsonParse.GeyJsonFrame))
if err != nil {
t.Fatalf("unexpected error: %s", err)
}
fn(v)
})
t.Run("testJsonIterParse", func(t *testing.T) {
v, err := JsonParse.Parse(s, JsonParse.SetParseFrame(JsonParse.JsonIterFrame))
if err != nil {
t.Fatalf("unexpected error: %s", err)
}
fn(v)
})
t.Run("testJsonParser", func(t *testing.T) {
v, err := JsonParse.Parse(s, JsonParse.SetParseFrame(JsonParse.JsonParserFrame))
if err != nil {
t.Fatalf("unexpected error: %s", err)
}
fn(v)
})
t.Run("testSonicJsonParse", func(t *testing.T) {
v, err := JsonParse.Parse(s, JsonParse.SetParseFrame(JsonParse.SonicFrame))
if err != nil {
t.Fatalf("unexpected error: %s", err)
}
fn(v)
})
}
六、 ngeyjson的设计
ngeyjson是一个立足于无反射的Json库。
序列化和反序列化
type Marshaler interface { MarshalJSON() ([]byte, error) }
type Unmarshaler interface { UnmarshalJSON([]byte) error }
go sdk的 json 提供了对外接口。
应用层可以实现 Marshaler 和 Unmarshaler , 达到无反射实现json的序列化和反序列化。
而对于复杂的Json, 一个是应用层处理比较麻烦,一个是不具有通用性。
可能这个项目序列反序列了特定结构,后续的项目可能还需要重新 实现。
通过参考easyjson和ffjson的实现,我们将其进一步发展,完全可以实现这样一种方式:
让程序来运行时自动生成序列和反序列的代码。这样的好处是:
1) 如果反序列的结构有变化,可以自适应,具有扩展性。
2) 不像 easyjson和ffjson那么麻烦,且具有侵入性。
3) 具有通用性,无论是自定义类型还是结构体类型都能完全适配.动态生成。
这样的弊端是开始动态生成的代码比较耗时,但也仅仅是耗时一次,还有出问题可能调试跟踪定位比较麻烦。
但随着这个框架能逐渐成熟的话,调试跟踪定位也会迎刃而解。
解析部分Json
这部分发展和参考了 fastjson的实现。但是没有做到sonic那么极致,还是在fastjson基础上的进一步完善优化。
后续有时间可能考虑再进一步的高效的实现。
相比较于 fastjson, ngeyjson的区别在于
1、结构不同
fastjson的Value结构:
type Value struct { o Object a []*Value s string t Type }
ngeyjson的Value结构:
type Value struct { o Object a []*Value spos int32 epos int32 t Type }
2、对 null 的支持
ngeyjson对null支持大小写,大写和小写混合同样支持.比如 Null
3、String的处理
fastjson的String的处理是个败笔,作者在注释中也说仅仅让用在测试。
ngeyjson对String的处理完全没有性能效率的问题.
4、转义符的处理
因为fastjson的String处理的不好,导致key对应的有转义符的字符串类型的值 并没有处理好。而ngeyjson完全支持。
5、后续迭代
fastjson已经好久不更新了......
七、结束语
欢迎大家通过 github 来下载 github.com/bcwtlch/nGoJsons , 通过进一步的使用来完善这个开源库。主要的出发点是方便大家来使用。github.com上有详细的说明使用和demo用例。
写这个开源库没用多久,测试和完善花费的时间更久。后续我还会开源一些有自己想法的方便使用的通用类的工具库。