jsonfield.go 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388
  1. // Copyright 2019 Yunion
  2. //
  3. // Licensed under the Apache License, Version 2.0 (the "License");
  4. // you may not use this file except in compliance with the License.
  5. // You may obtain a copy of the License at
  6. //
  7. // http://www.apache.org/licenses/LICENSE-2.0
  8. //
  9. // Unless required by applicable law or agreed to in writing, software
  10. // distributed under the License is distributed on an "AS IS" BASIS,
  11. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12. // See the License for the specific language governing permissions and
  13. // limitations under the License.
  14. package reflectutils
  15. import (
  16. "reflect"
  17. "strings"
  18. "sync"
  19. "yunion.io/x/pkg/gotypes"
  20. "yunion.io/x/pkg/utils"
  21. )
  22. // SStructFieldInfo describes struct field, especially behavior for (json)
  23. // marshal
  24. //
  25. // This struct has unexported fields initialized by exported functions in this
  26. // package. Do not construct a literal or modify the exported fields in an
  27. // unmanaged way
  28. type SStructFieldInfo struct {
  29. // True if the field has json tag `json:"-"`
  30. Ignore bool
  31. OmitEmpty bool
  32. OmitFalse bool
  33. OmitZero bool
  34. // Name can take the following values, in descreasing preference
  35. //
  36. // 1. value of "name" tag, e.g. `name:"a-name"`
  37. // 2. name of "json" tag, when it's not for ignoration
  38. // 3. kebab form of FieldName concatenated with "_" when Ignore is false
  39. // 4. empty string
  40. Name string
  41. FieldName string
  42. kebabFieldName string
  43. ForceString bool
  44. Tags map[string]string
  45. Aliases []string
  46. }
  47. func (s *SStructFieldInfo) updateTags(k, v string) {
  48. s.Tags[k] = v
  49. }
  50. func (s SStructFieldInfo) deepCopy() *SStructFieldInfo {
  51. scopy := SStructFieldInfo{
  52. Ignore: s.Ignore,
  53. OmitEmpty: s.OmitEmpty,
  54. OmitFalse: s.OmitFalse,
  55. OmitZero: s.OmitZero,
  56. Name: s.Name,
  57. FieldName: s.FieldName,
  58. ForceString: s.ForceString,
  59. kebabFieldName: s.kebabFieldName,
  60. }
  61. tags := make(map[string]string, len(s.Tags))
  62. for k, v := range s.Tags {
  63. tags[k] = v
  64. }
  65. scopy.Tags = tags
  66. aliases := make([]string, len(s.Aliases))
  67. copy(aliases, s.Aliases)
  68. scopy.Aliases = aliases
  69. return &scopy
  70. }
  71. func ParseStructFieldJsonInfo(sf reflect.StructField) SStructFieldInfo {
  72. return ParseFieldJsonInfo(sf.Name, sf.Tag)
  73. }
  74. func ParseFieldJsonInfo(name string, tag reflect.StructTag) SStructFieldInfo {
  75. info := SStructFieldInfo{}
  76. info.FieldName = name
  77. info.kebabFieldName = utils.CamelSplit(name, "_")
  78. info.OmitEmpty = true
  79. info.OmitZero = false
  80. info.OmitFalse = false
  81. info.Tags = utils.TagMap(tag)
  82. if val, ok := info.Tags["json"]; ok {
  83. keys := strings.Split(val, ",")
  84. if len(keys) > 0 {
  85. if keys[0] == "-" {
  86. if len(keys) > 1 {
  87. info.Name = keys[0]
  88. } else {
  89. info.Ignore = true
  90. }
  91. } else {
  92. info.Name = keys[0]
  93. }
  94. }
  95. if len(keys) > 1 {
  96. for _, k := range keys[1:] {
  97. switch strings.ToLower(k) {
  98. case "omitempty":
  99. info.OmitEmpty = true
  100. case "allowempty":
  101. info.OmitEmpty = false
  102. case "omitzero":
  103. info.OmitZero = true
  104. case "allowzero":
  105. info.OmitZero = false
  106. case "omitfalse":
  107. info.OmitFalse = true
  108. case "allowfalse":
  109. info.OmitFalse = false
  110. case "string":
  111. info.ForceString = true
  112. }
  113. }
  114. }
  115. }
  116. if val, ok := info.Tags["name"]; ok {
  117. info.Name = val
  118. }
  119. if !info.Ignore && len(info.Name) == 0 {
  120. info.Name = info.kebabFieldName
  121. }
  122. if val, ok := info.Tags["alias"]; !info.Ignore && ok {
  123. info.Aliases = strings.Split(val, ",")
  124. }
  125. return info
  126. }
  127. // MarshalName returns Name when it's not empty, otherwise it returns kebab
  128. // form of the field name concatenated with "_"
  129. func (info *SStructFieldInfo) MarshalName() string {
  130. if len(info.Name) > 0 {
  131. return info.Name
  132. }
  133. return info.kebabFieldName
  134. }
  135. type SStructFieldValue struct {
  136. Info *SStructFieldInfo
  137. Value reflect.Value
  138. Parent *SEmbedStructFieldValue
  139. }
  140. type SEmbedStructFieldValue struct {
  141. Field reflect.Value
  142. Value reflect.Value
  143. }
  144. type SStructFieldValueSet []SStructFieldValue
  145. func FetchStructFieldValueSet(dataValue reflect.Value) SStructFieldValueSet {
  146. return expandAmbiguousPrefix(fetchStructFieldValueSet(dataValue, false))
  147. }
  148. func FetchStructFieldValueSetForWrite(dataValue reflect.Value) SStructFieldValueSet {
  149. return expandAmbiguousPrefix(fetchStructFieldValueSet(dataValue, true))
  150. }
  151. func FetchAllStructFieldValueSet(dataValue reflect.Value) SStructFieldValueSet {
  152. return expandAmbiguousPrefix(fetchStructFieldValueSet2(dataValue, false, nil, true))
  153. }
  154. func FetchAllStructFieldValueSetForWrite(dataValue reflect.Value) SStructFieldValueSet {
  155. return expandAmbiguousPrefix(fetchStructFieldValueSet2(dataValue, true, nil, true))
  156. }
  157. type sStructFieldInfoMap map[string]SStructFieldInfo
  158. func newStructFieldInfoMap(caps int) sStructFieldInfoMap {
  159. return make(map[string]SStructFieldInfo, caps)
  160. }
  161. var structFieldInfoCache sync.Map
  162. func fetchCacheStructFieldInfos(dataType reflect.Type) sStructFieldInfoMap {
  163. if r, ok := structFieldInfoCache.Load(dataType); ok {
  164. return r.(sStructFieldInfoMap)
  165. }
  166. infos := fetchStructFieldInfos(dataType)
  167. structFieldInfoCache.Store(dataType, infos)
  168. return infos
  169. }
  170. func fetchStructFieldInfos(dataType reflect.Type) sStructFieldInfoMap {
  171. smap := newStructFieldInfoMap(dataType.NumField())
  172. for i := 0; i < dataType.NumField(); i += 1 {
  173. sf := dataType.Field(i)
  174. if !gotypes.IsFieldExportable(sf.Name) {
  175. continue
  176. }
  177. if sf.Anonymous {
  178. // call ParseStructFieldJsonInfo for sf if sft.Kind() is reflect.Interface:
  179. // if the corresponding value is reflect.Struct, this item in fieldInfos will be ignored,
  180. // otherwise this item in fieldInfos will be used correctly
  181. sft := sf.Type
  182. if sft.Kind() == reflect.Ptr {
  183. sft = sft.Elem()
  184. }
  185. if sft.Kind() == reflect.Struct && sft != gotypes.TimeType {
  186. continue
  187. }
  188. }
  189. smap[sf.Name] = ParseStructFieldJsonInfo(sf)
  190. }
  191. return smap
  192. }
  193. func fetchStructFieldValueSet(dataValue reflect.Value, allocatePtr bool) SStructFieldValueSet {
  194. return fetchStructFieldValueSet2(dataValue, allocatePtr, nil, false)
  195. }
  196. func fetchStructFieldValueSet2(dataValue reflect.Value, allocatePtr bool, tags map[string]string, includeIgnore bool) SStructFieldValueSet {
  197. return fetchStructFieldValueSet3(dataValue, allocatePtr, tags, includeIgnore, nil)
  198. }
  199. func fetchStructFieldValueSet3(dataValue reflect.Value, allocatePtr bool, tags map[string]string, includeIgnore bool, parent *SEmbedStructFieldValue) SStructFieldValueSet {
  200. fields := SStructFieldValueSet{}
  201. dataType := dataValue.Type()
  202. fieldInfos := fetchCacheStructFieldInfos(dataType)
  203. for i := 0; i < dataType.NumField(); i += 1 {
  204. sf := dataType.Field(i)
  205. // ignore unexported field altogether
  206. if !gotypes.IsFieldExportable(sf.Name) {
  207. continue
  208. }
  209. fv := dataValue.Field(i)
  210. if !fv.IsValid() {
  211. continue
  212. }
  213. var efv *SEmbedStructFieldValue
  214. if sf.Anonymous {
  215. // T, *T
  216. switch fv.Kind() {
  217. case reflect.Ptr, reflect.Interface:
  218. if !fv.IsValid() {
  219. continue
  220. }
  221. if fv.IsNil() {
  222. if fv.Kind() == reflect.Ptr && allocatePtr {
  223. fv.Set(reflect.New(fv.Type().Elem()))
  224. } else if fv.Kind() == reflect.Ptr && !allocatePtr {
  225. efv = &SEmbedStructFieldValue{
  226. Field: fv,
  227. Value: reflect.New(fv.Type().Elem()),
  228. }
  229. fv = efv.Value
  230. } else {
  231. continue
  232. }
  233. }
  234. fv = fv.Elem()
  235. }
  236. // note that we regard anonymous interface field the
  237. // same as with anonymous struct field. This is
  238. // different from how encoding/json handles struct
  239. // field of interface type.
  240. if fv.Kind() == reflect.Struct && sf.Type != gotypes.TimeType {
  241. anonymousTags := utils.TagMap(sf.Tag)
  242. subfields := fetchStructFieldValueSet3(fv, allocatePtr, anonymousTags, includeIgnore, efv)
  243. fields = append(fields, subfields...)
  244. continue
  245. }
  246. }
  247. fieldInfo := fieldInfos[sf.Name].deepCopy()
  248. if !fieldInfo.Ignore || includeIgnore {
  249. structFieldVaule := SStructFieldValue{
  250. Info: fieldInfo,
  251. Value: fv,
  252. }
  253. if parent != nil {
  254. structFieldVaule.Parent = parent
  255. }
  256. fields = append(fields, structFieldVaule)
  257. }
  258. }
  259. if len(tags) > 0 {
  260. for i := range fields {
  261. fieldName := fields[i].Info.MarshalName()
  262. for k, v := range tags {
  263. target := ""
  264. pos := strings.Index(k, "->")
  265. if pos > 0 {
  266. target = k[:pos]
  267. k = k[pos+2:]
  268. }
  269. if len(target) > 0 && target != fieldName {
  270. continue
  271. }
  272. fields[i].Info.updateTags(k, v)
  273. }
  274. }
  275. }
  276. return fields
  277. }
  278. func (fields SStructFieldValueSet) GetStructFieldIndex(name string) int {
  279. indexes := fields.GetStructFieldIndexes(name)
  280. if len(indexes) > 0 {
  281. return indexes[0]
  282. }
  283. return -1
  284. }
  285. func (fields SStructFieldValueSet) GetStructFieldIndexes(name string) []int {
  286. return fields.GetStructFieldIndexes2(name, false)
  287. }
  288. func (fields SStructFieldValueSet) GetStructFieldIndexes2(name string, strictMode bool) []int {
  289. var (
  290. ret []int
  291. kebabName string
  292. capName string
  293. )
  294. if !strictMode && len(fields) > 0 {
  295. kebabName = utils.CamelSplit(name, "_")
  296. capName = utils.Capitalize(name)
  297. }
  298. for i := range fields {
  299. info := fields[i].Info
  300. if info.Ignore {
  301. continue
  302. }
  303. if info.MarshalName() == name {
  304. ret = append(ret, i)
  305. continue
  306. }
  307. if !strictMode {
  308. if info.kebabFieldName == kebabName {
  309. ret = append(ret, i)
  310. } else if info.FieldName == name {
  311. ret = append(ret, i)
  312. } else if info.FieldName == capName {
  313. ret = append(ret, i)
  314. } else if len(info.Aliases) > 0 && utils.IsInArray(name, info.Aliases) {
  315. ret = append(ret, i)
  316. }
  317. }
  318. }
  319. return ret
  320. }
  321. func (fields SStructFieldValueSet) GetStructFieldIndexesMap() map[string][]int {
  322. keyIndexMap := make(map[string][]int)
  323. for i := range fields {
  324. if fields[i].Info.Ignore {
  325. continue
  326. }
  327. key := fields[i].Info.MarshalName()
  328. values, ok := keyIndexMap[key]
  329. if !ok {
  330. values = make([]int, 0, 2)
  331. }
  332. keyIndexMap[key] = append(values, i)
  333. }
  334. return keyIndexMap
  335. }
  336. func (set SStructFieldValueSet) GetValue(name string) (reflect.Value, bool) {
  337. idx := set.GetStructFieldIndex(name)
  338. if idx < 0 {
  339. return reflect.Value{}, false
  340. }
  341. return set[idx].Value, true
  342. }
  343. func (set SStructFieldValueSet) GetInterface(name string) (interface{}, bool) {
  344. idx := set.GetStructFieldIndex(name)
  345. if idx < 0 {
  346. return nil, false
  347. }
  348. if set[idx].Value.CanInterface() {
  349. return set[idx].Value.Interface(), true
  350. }
  351. return nil, false
  352. }