-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathmarshalling.go
59 lines (44 loc) · 1.1 KB
/
marshalling.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
package gotils
import (
"encoding/json"
"reflect"
)
type CastMap map[string]func(interface{}) (interface{}, error)
func MarshalWithCasts(b []byte, emptyObj interface{}, castFns CastMap) (interface{}, error) {
ttype := reflect.TypeOf(emptyObj)
fields := []reflect.StructField{}
for i := 0; i < ttype.NumField(); i++ {
f := ttype.Field(i)
if _, ok := castFns[f.Name]; ok {
f.Type = reflect.TypeOf((*interface{})(nil)).Elem()
}
fields = append(fields, f)
}
t := reflect.StructOf(fields)
obj := reflect.New(t).Interface()
newObj := reflect.New(ttype).Elem()
err := json.Unmarshal(b, obj)
if err != nil {
return newObj.Interface(), err
}
for i := 0; i < ttype.NumField(); i++ {
ft := t.Field(i)
fv := reflect.ValueOf(obj).Elem().Field(i)
if !fv.CanSet() || fv.Interface() == nil {
continue
}
if fn, ok := castFns[ft.Name]; ok {
s, err := fn(fv.Interface())
if err != nil {
return emptyObj, err
}
fv = reflect.ValueOf(s)
}
nfv := newObj.Field(i)
// Should probably alwasy be true?
if nfv.CanSet() {
nfv.Set(fv)
}
}
return newObj.Interface(), nil
}