github.com/bytedance/go-tagexpr@v2.7.5-0.20210114074101-de5b8743ad85+incompatible/binding/gjson/gjson.go (about) 1 // The MIT License (MIT) 2 3 // Copyright (c) 2016 Josh Baker 4 5 // Permission is hereby granted, free of charge, to any person obtaining a copy of 6 // this software and associated documentation files (the "Software"), to deal in 7 // the Software without restriction, including without limitation the rights to 8 // use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 9 // the Software, and to permit persons to whom the Software is furnished to do so, 10 // subject to the following conditions: 11 12 // The above copyright notice and this permission notice shall be included in all 13 // copies or substantial portions of the Software. 14 15 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 17 // FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 18 // COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 19 // IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 20 // CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 21 22 package gjson 23 24 import ( 25 "encoding/base64" 26 "encoding/json" 27 "reflect" 28 "strings" 29 "sync" 30 31 "github.com/henrylee2cn/ameda" 32 "github.com/henrylee2cn/goutil/tpack" 33 "github.com/tidwall/gjson" 34 35 "github.com/bytedance/go-tagexpr/binding" 36 ) 37 38 var fieldsmu sync.RWMutex 39 var fields = make(map[uintptr]map[string]int) 40 41 func init() { 42 gjson.DisableModifiers = true 43 } 44 45 // UseJSONUnmarshaler reset the JSON Unmarshaler of binding. 46 func UseJSONUnmarshaler() { 47 binding.ResetJSONUnmarshaler(unmarshal) 48 } 49 50 // unmarshal unmarshal JSON, old version compatible. 51 func unmarshal(data []byte, v interface{}) error { 52 val, ok := v.(reflect.Value) 53 if !ok { 54 val = reflect.ValueOf(v) 55 } 56 assign(gjson.Parse(ameda.UnsafeBytesToString(data)), val) 57 return nil 58 } 59 60 // assign unmarshal 61 func assign(jsval gjson.Result, goval reflect.Value) { 62 if jsval.Type == gjson.Null { 63 return 64 } 65 t := goval.Type() 66 switch goval.Kind() { 67 default: 68 case reflect.Ptr: 69 if !goval.IsNil() { 70 newval := reflect.New(goval.Elem().Type()) 71 assign(jsval, newval.Elem()) 72 goval.Elem().Set(newval.Elem()) 73 } else { 74 newval := reflect.New(t.Elem()) 75 assign(jsval, newval.Elem()) 76 goval.Set(newval) 77 } 78 case reflect.Struct: 79 runtimeTypeID := tpack.From(goval).RuntimeTypeID() 80 fieldsmu.RLock() 81 sf := fields[runtimeTypeID] 82 fieldsmu.RUnlock() 83 if sf == nil { 84 fieldsmu.Lock() 85 sf = make(map[string]int) 86 numField := t.NumField() 87 for i := 0; i < numField; i++ { 88 f := t.Field(i) 89 tag := strings.Split(f.Tag.Get("json"), ",")[0] 90 if tag != "-" { 91 if tag != "" { 92 sf[tag] = i 93 sf[f.Name] = i 94 } else { 95 sf[f.Name] = i 96 } 97 } 98 } 99 fields[runtimeTypeID] = sf 100 fieldsmu.Unlock() 101 } 102 jsval.ForEach(func(key, value gjson.Result) bool { 103 if idx, ok := sf[key.Str]; ok { 104 f := goval.Field(idx) 105 if f.CanSet() { 106 assign(value, f) 107 } 108 } 109 return true 110 }) 111 case reflect.Slice: 112 if t.Elem().Kind() == reflect.Uint8 && jsval.Type == gjson.String { 113 data, _ := base64.StdEncoding.DecodeString(jsval.String()) 114 goval.Set(reflect.ValueOf(data)) 115 } else { 116 jsvals := jsval.Array() 117 slice := reflect.MakeSlice(t, len(jsvals), len(jsvals)) 118 for i := 0; i < len(jsvals); i++ { 119 assign(jsvals[i], slice.Index(i)) 120 } 121 goval.Set(slice) 122 } 123 case reflect.Array: 124 i, n := 0, goval.Len() 125 jsval.ForEach(func(_, value gjson.Result) bool { 126 if i == n { 127 return false 128 } 129 assign(value, goval.Index(i)) 130 i++ 131 return true 132 }) 133 case reflect.Map: 134 if jsval.Type == gjson.JSON && t.Key().Kind() == reflect.String { 135 if t.Elem().Kind() == reflect.Interface { 136 goval.Set(reflect.ValueOf(jsval.Value())) 137 } else { 138 if goval.IsNil() { 139 goval.Set(reflect.MakeMap(t)) 140 } 141 valType := t.Elem() 142 jsval.ForEach(func(key, value gjson.Result) bool { 143 val := reflect.New(valType) 144 assign(value, val) 145 goval.SetMapIndex(reflect.ValueOf(key.String()), val.Elem()) 146 return true 147 }) 148 } 149 } 150 case reflect.Interface: 151 goval.Set(reflect.ValueOf(jsval.Value())) 152 case reflect.Bool: 153 goval.SetBool(jsval.Bool()) 154 case reflect.Float32, reflect.Float64: 155 goval.SetFloat(jsval.Float()) 156 case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: 157 goval.SetInt(jsval.Int()) 158 case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64: 159 goval.SetUint(jsval.Uint()) 160 case reflect.String: 161 goval.SetString(jsval.String()) 162 } 163 if len(t.PkgPath()) > 0 { 164 v := goval.Addr() 165 if v.Type().NumMethod() > 0 { 166 if u, ok := v.Interface().(json.Unmarshaler); ok { 167 u.UnmarshalJSON([]byte(jsval.Raw)) 168 } 169 } 170 } 171 }