2016-12-04 23:01:42 +08:00
|
|
|
# json iterator (jsoniter)
|
2016-12-01 00:56:25 +08:00
|
|
|
|
2016-12-04 23:01:42 +08:00
|
|
|
faster than DOM, more usable than SAX/StAX
|
2016-12-01 00:56:25 +08:00
|
|
|
|
2016-12-06 11:25:48 +08:00
|
|
|
# Why json iterator?
|
2016-12-01 00:56:25 +08:00
|
|
|
|
2016-12-06 11:25:48 +08:00
|
|
|
## 1. It is faster
|
2016-12-01 00:56:25 +08:00
|
|
|
|
2016-12-06 11:25:48 +08:00
|
|
|
jsoniter can work as drop in replacement for json.Unmarshal, with or without reflection. Unlike https://github.com/pquerna/ffjson
|
|
|
|
jsoniter does not require `go generate`
|
2016-12-05 13:31:59 +08:00
|
|
|
|
2016-12-06 11:25:48 +08:00
|
|
|
for performance numbers, see https://github.com/json-iterator/go-benchmark
|
2016-12-01 23:25:29 +08:00
|
|
|
|
2016-12-06 11:25:48 +08:00
|
|
|
## 2. io.Reader as input
|
2016-12-05 13:31:59 +08:00
|
|
|
|
2016-12-06 11:25:48 +08:00
|
|
|
jsoniter does not read the whole json into memory, it parse the document in a streaming way. Unlike https://github.com/pquerna/ffjson
|
|
|
|
it requires []byte as input.
|
2016-12-01 23:25:29 +08:00
|
|
|
|
2016-12-06 11:25:48 +08:00
|
|
|
## 3. Pull style api
|
2016-12-01 23:25:29 +08:00
|
|
|
|
2016-12-06 11:25:48 +08:00
|
|
|
jsoniter can be used just like json.Unmarshal, for example
|
2016-12-01 23:25:29 +08:00
|
|
|
|
|
|
|
```
|
2016-12-06 11:25:48 +08:00
|
|
|
type StructOfTag struct {
|
|
|
|
field1 string `json:"field-1"`
|
|
|
|
field2 string `json:"-"`
|
|
|
|
field3 int `json:",string"`
|
2016-12-01 23:25:29 +08:00
|
|
|
}
|
|
|
|
|
2016-12-06 11:25:48 +08:00
|
|
|
struct_ := StructOfTag{}
|
|
|
|
jsoniter.Unmarshal(`{"field-1": "hello", "field2": "", "field3": "100"}`, &struct_)
|
2016-12-01 23:25:29 +08:00
|
|
|
```
|
|
|
|
|
2016-12-06 11:25:48 +08:00
|
|
|
But it allows you to go down one level lower, to control the parsing process using pull style api (like StAX, if you
|
|
|
|
know what I mean). Here is just a demo of what you can do
|
2016-12-01 23:25:29 +08:00
|
|
|
|
|
|
|
```
|
2016-12-06 11:25:48 +08:00
|
|
|
iter := jsoniter.ParseString(`[1,2,3]`)
|
|
|
|
for iter.ReadArray() {
|
|
|
|
iter.ReadUint64()
|
2016-12-01 23:25:29 +08:00
|
|
|
}
|
2016-12-05 13:31:59 +08:00
|
|
|
```
|
|
|
|
|
2016-12-06 11:25:48 +08:00
|
|
|
## 4. Customization
|
2016-12-05 13:31:59 +08:00
|
|
|
|
|
|
|
Of course, you can use the low level pull api to do anything you like. But most of the time,
|
|
|
|
reflection based api is fast enough. How to control the parsing process when we are using the reflection api?
|
|
|
|
json.Unmarshaller is not flexible enough. Jsoniter provides much better customizability.
|
|
|
|
|
|
|
|
```
|
|
|
|
func Test_customize_type_decoder(t *testing.T) {
|
|
|
|
RegisterTypeDecoder("time.Time", func(ptr unsafe.Pointer, iter *Iterator) {
|
|
|
|
t, err := time.ParseInLocation("2006-01-02 15:04:05", iter.ReadString(), time.UTC)
|
|
|
|
if err != nil {
|
|
|
|
iter.Error = err
|
|
|
|
return
|
|
|
|
}
|
|
|
|
*((*time.Time)(ptr)) = t
|
|
|
|
})
|
|
|
|
defer ClearDecoders()
|
|
|
|
val := time.Time{}
|
|
|
|
err := Unmarshal([]byte(`"2016-12-05 08:43:28"`), &val)
|
|
|
|
if err != nil {
|
|
|
|
t.Fatal(err)
|
|
|
|
}
|
|
|
|
year, month, day := val.Date()
|
|
|
|
if year != 2016 || month != 12 || day != 5 {
|
|
|
|
t.Fatal(val)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
```
|
|
|
|
|
2016-12-06 11:25:48 +08:00
|
|
|
there is no way to add json.Unmarshaller to time.Time as the type is not defined by you (type alias time.Time is not fun to use).
|
|
|
|
Using jsoniter, we can.
|
2016-12-05 13:31:59 +08:00
|
|
|
|
|
|
|
```
|
|
|
|
type Tom struct {
|
|
|
|
field1 string
|
|
|
|
}
|
|
|
|
|
|
|
|
func Test_customize_field_decoder(t *testing.T) {
|
|
|
|
RegisterFieldDecoder("jsoniter.Tom", "field1", func(ptr unsafe.Pointer, iter *Iterator) {
|
|
|
|
*((*string)(ptr)) = strconv.Itoa(iter.ReadInt())
|
|
|
|
})
|
|
|
|
defer ClearDecoders()
|
|
|
|
tom := Tom{}
|
|
|
|
err := Unmarshal([]byte(`{"field1": 100}`), &tom)
|
|
|
|
if err != nil {
|
|
|
|
t.Fatal(err)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
```
|
|
|
|
|
|
|
|
It is very common the input json has certain fields massed up. We want string, but it is int, etc. The old way is to
|
|
|
|
define a struct of exact type like the json. Then we convert from one struct to a new struct. It is just too much work.
|
|
|
|
Using jsoniter you can tweak the field conversion.
|
|
|
|
|
2016-12-06 11:25:48 +08:00
|
|
|
# Why not json iterator?
|
|
|
|
|
|
|
|
jsoniter does not plan to support `map[string]interface{}`, period.
|