Skip to content

Commit 53c80a5

Browse files
authored
Update go-extension.md
1 parent 869c14c commit 53c80a5

File tree

1 file changed

+83
-0
lines changed

1 file changed

+83
-0
lines changed

go-extension.md

Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,3 +14,86 @@ All kinds of annotation support can be implemented using the callback. Also the
1414
slowing down the runtime execution.
1515

1616
# Customize type decoding
17+
18+
```go
19+
RegisterTypeDecoder("time.Time", func(ptr unsafe.Pointer, iter *Iterator) {
20+
t, err := time.ParseInLocation("2006-01-02 15:04:05", iter.ReadString(), time.UTC)
21+
if err != nil {
22+
iter.Error = err
23+
return
24+
}
25+
*((*time.Time)(ptr)) = t
26+
})
27+
defer ClearDecoders()
28+
val := time.Time{}
29+
err := Unmarshal([]byte(`"2016-12-05 08:43:28"`), &val)
30+
if err != nil {
31+
t.Fatal(err)
32+
}
33+
year, month, day := val.Date()
34+
if year != 2016 || month != 12 || day != 5 {
35+
t.Fatal(val)
36+
}
37+
```
38+
39+
The callback will be called for the registered type. The first argument is a pointer to the instance, the second argument is the iterator pointint to the next value to read.
40+
41+
# Customize field decoding
42+
43+
We can also control how the deconding is done at the field level. For example if the input is int, and we want to bind it to a string typed field.
44+
45+
```go
46+
type Tom struct {
47+
field1 string
48+
}
49+
```
50+
51+
and the input `{"field1": 100}`. We need to register a field decoder:
52+
53+
```go
54+
RegisterFieldDecoder("jsoniter.Tom", "field1", func(ptr unsafe.Pointer, iter *Iterator) {
55+
*((*string)(ptr)) = strconv.Itoa(iter.ReadInt())
56+
})
57+
defer ClearDecoders()
58+
tom := Tom{}
59+
err := Unmarshal([]byte(`{"field1": 100}`), &tom)
60+
if err != nil {
61+
t.Fatal(err)
62+
}
63+
```
64+
65+
It is nearly the same as type decoder, just add a argument to specify the field name.
66+
67+
# Customize field mapping
68+
69+
When the field name does not match the json input, we can customize it by callback. The callback will be provided with `reflect.StructField`, which has tags for the field.
70+
71+
```go
72+
RegisterExtension(func(type_ reflect.Type, field *reflect.StructField) ([]string, DecoderFunc) {
73+
if (type_.String() == "jsoniter.Tom" && field.Name == "field1") {
74+
return []string{"field-1"}, nil
75+
}
76+
return nil, nil
77+
})
78+
tom := Tom{}
79+
err := Unmarshal([]byte(`{"field-1": "100"}`), &tom)
80+
if err != nil {
81+
t.Fatal(err)
82+
}
83+
if tom.field1 != "100" {
84+
t.Fatal(tom.field1)
85+
}
86+
```
87+
88+
The extension definition is
89+
90+
```go
91+
type ExtensionFunc func(type_ reflect.Type, field *reflect.StructField) ([]string, DecoderFunc)
92+
```
93+
94+
* type is the type being decoded
95+
* field is the field being decoded. this could be nil, if customizing the type itself
96+
* first return value is alternative field names for the field, only used when field is not nil
97+
* second return value is the decoder to decode the type or just the field, depending on field is nil or not
98+
99+

0 commit comments

Comments
 (0)