|
@@ -6,6 +6,8 @@ for performance numbers, see https://github.com/json-iterator/go-benchmark
|
|
|
|
|
|
|
|
# DOM style api
|
|
# DOM style api
|
|
|
|
|
|
|
|
|
|
+Jsoniter can work as drop in replacement for json.Unmarshal
|
|
|
|
|
+
|
|
|
```
|
|
```
|
|
|
type StructOfTag struct {
|
|
type StructOfTag struct {
|
|
|
field1 string `json:"field-1"`
|
|
field1 string `json:"field-1"`
|
|
@@ -32,6 +34,9 @@ func Test_reflect_struct_tag_field(t *testing.T) {
|
|
|
|
|
|
|
|
# StAX style api
|
|
# StAX style api
|
|
|
|
|
|
|
|
|
|
+When you need the maximum performance, the pull style api allows you to control every bit of parsing process. You
|
|
|
|
|
+can bind value to object without reflection, or you can calculate the sum of array on the fly without intermediate objects.
|
|
|
|
|
+
|
|
|
Array
|
|
Array
|
|
|
|
|
|
|
|
```
|
|
```
|
|
@@ -75,4 +80,58 @@ iter.ReadArray()
|
|
|
if iter.ReadString() != "b" {
|
|
if iter.ReadString() != "b" {
|
|
|
t.FailNow()
|
|
t.FailNow()
|
|
|
}
|
|
}
|
|
|
-```
|
|
|
|
|
|
|
+```
|
|
|
|
|
+
|
|
|
|
|
+# Customization
|
|
|
|
|
+
|
|
|
|
|
+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)
|
|
|
|
|
+ }
|
|
|
|
|
+}
|
|
|
|
|
+```
|
|
|
|
|
+
|
|
|
|
|
+there is no way to add json.Unmarshaller to time.Time as the type is not defined by you. Using jsoniter, we can.
|
|
|
|
|
+
|
|
|
|
|
+```
|
|
|
|
|
+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.
|
|
|
|
|
+
|