gconv_struct.go 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586
  1. // Copyright GoFrame Author(https://goframe.org). All Rights Reserved.
  2. //
  3. // This Source Code Form is subject to the terms of the MIT License.
  4. // If a copy of the MIT was not distributed with this file,
  5. // You can obtain one at https://github.com/gogf/gf.
  6. package gconv
  7. import (
  8. "reflect"
  9. "strings"
  10. "github.com/gogf/gf/v2/errors/gcode"
  11. "github.com/gogf/gf/v2/errors/gerror"
  12. "github.com/gogf/gf/v2/internal/empty"
  13. "github.com/gogf/gf/v2/internal/json"
  14. "github.com/gogf/gf/v2/internal/utils"
  15. "github.com/gogf/gf/v2/os/gstructs"
  16. )
  17. // Struct maps the params key-value pairs to the corresponding struct object's attributes.
  18. // The third parameter `mapping` is unnecessary, indicating the mapping rules between the
  19. // custom key name and the attribute name(case-sensitive).
  20. //
  21. // Note:
  22. // 1. The `params` can be any type of map/struct, usually a map.
  23. // 2. The `pointer` should be type of *struct/**struct, which is a pointer to struct object
  24. // or struct pointer.
  25. // 3. Only the public attributes of struct object can be mapped.
  26. // 4. If `params` is a map, the key of the map `params` can be lowercase.
  27. // It will automatically convert the first letter of the key to uppercase
  28. // in mapping procedure to do the matching.
  29. // It ignores the map key, if it does not match.
  30. func Struct(params interface{}, pointer interface{}, mapping ...map[string]string) (err error) {
  31. return Scan(params, pointer, mapping...)
  32. }
  33. // StructTag acts as Struct but also with support for priority tag feature, which retrieves the
  34. // specified tags for `params` key-value items to struct attribute names mapping.
  35. // The parameter `priorityTag` supports multiple tags that can be joined with char ','.
  36. func StructTag(params interface{}, pointer interface{}, priorityTag string) (err error) {
  37. return doStruct(params, pointer, nil, priorityTag)
  38. }
  39. // doStructWithJsonCheck checks if given `params` is JSON, it then uses json.Unmarshal doing the converting.
  40. func doStructWithJsonCheck(params interface{}, pointer interface{}) (err error, ok bool) {
  41. switch r := params.(type) {
  42. case []byte:
  43. if json.Valid(r) {
  44. if rv, ok := pointer.(reflect.Value); ok {
  45. if rv.Kind() == reflect.Ptr {
  46. if rv.IsNil() {
  47. return nil, false
  48. }
  49. return json.UnmarshalUseNumber(r, rv.Interface()), true
  50. } else if rv.CanAddr() {
  51. return json.UnmarshalUseNumber(r, rv.Addr().Interface()), true
  52. }
  53. } else {
  54. return json.UnmarshalUseNumber(r, pointer), true
  55. }
  56. }
  57. case string:
  58. if paramsBytes := []byte(r); json.Valid(paramsBytes) {
  59. if rv, ok := pointer.(reflect.Value); ok {
  60. if rv.Kind() == reflect.Ptr {
  61. if rv.IsNil() {
  62. return nil, false
  63. }
  64. return json.UnmarshalUseNumber(paramsBytes, rv.Interface()), true
  65. } else if rv.CanAddr() {
  66. return json.UnmarshalUseNumber(paramsBytes, rv.Addr().Interface()), true
  67. }
  68. } else {
  69. return json.UnmarshalUseNumber(paramsBytes, pointer), true
  70. }
  71. }
  72. default:
  73. // The `params` might be struct that implements interface function Interface, eg: gvar.Var.
  74. if v, ok := params.(iInterface); ok {
  75. return doStructWithJsonCheck(v.Interface(), pointer)
  76. }
  77. }
  78. return nil, false
  79. }
  80. // doStruct is the core internal converting function for any data to struct.
  81. func doStruct(params interface{}, pointer interface{}, mapping map[string]string, priorityTag string) (err error) {
  82. if params == nil {
  83. // If `params` is nil, no conversion.
  84. return nil
  85. }
  86. if pointer == nil {
  87. return gerror.NewCode(gcode.CodeInvalidParameter, "object pointer cannot be nil")
  88. }
  89. defer func() {
  90. // Catch the panic, especially the reflection operation panics.
  91. if exception := recover(); exception != nil {
  92. if v, ok := exception.(error); ok && gerror.HasStack(v) {
  93. err = v
  94. } else {
  95. err = gerror.NewCodeSkipf(gcode.CodeInternalError, 1, "%+v", exception)
  96. }
  97. }
  98. }()
  99. // JSON content converting.
  100. err, ok := doStructWithJsonCheck(params, pointer)
  101. if err != nil {
  102. return err
  103. }
  104. if ok {
  105. return nil
  106. }
  107. var (
  108. paramsReflectValue reflect.Value
  109. paramsInterface interface{} // DO NOT use `params` directly as it might be type `reflect.Value`
  110. pointerReflectValue reflect.Value
  111. pointerReflectKind reflect.Kind
  112. pointerElemReflectValue reflect.Value // The pointed element.
  113. )
  114. if v, ok := params.(reflect.Value); ok {
  115. paramsReflectValue = v
  116. } else {
  117. paramsReflectValue = reflect.ValueOf(params)
  118. }
  119. paramsInterface = paramsReflectValue.Interface()
  120. if v, ok := pointer.(reflect.Value); ok {
  121. pointerReflectValue = v
  122. pointerElemReflectValue = v
  123. } else {
  124. pointerReflectValue = reflect.ValueOf(pointer)
  125. pointerReflectKind = pointerReflectValue.Kind()
  126. if pointerReflectKind != reflect.Ptr {
  127. return gerror.NewCodef(gcode.CodeInvalidParameter, "object pointer should be type of '*struct', but got '%v'", pointerReflectKind)
  128. }
  129. // Using IsNil on reflect.Ptr variable is OK.
  130. if !pointerReflectValue.IsValid() || pointerReflectValue.IsNil() {
  131. return gerror.NewCode(gcode.CodeInvalidParameter, "object pointer cannot be nil")
  132. }
  133. pointerElemReflectValue = pointerReflectValue.Elem()
  134. }
  135. // If `params` and `pointer` are the same type, the do directly assignment.
  136. // For performance enhancement purpose.
  137. if pointerElemReflectValue.IsValid() && pointerElemReflectValue.Type() == paramsReflectValue.Type() {
  138. pointerElemReflectValue.Set(paramsReflectValue)
  139. return nil
  140. }
  141. // Normal unmarshalling interfaces checks.
  142. if err, ok = bindVarToReflectValueWithInterfaceCheck(pointerReflectValue, paramsInterface); ok {
  143. return err
  144. }
  145. // It automatically creates struct object if necessary.
  146. // For example, if `pointer` is **User, then `elem` is *User, which is a pointer to User.
  147. if pointerElemReflectValue.Kind() == reflect.Ptr {
  148. if !pointerElemReflectValue.IsValid() || pointerElemReflectValue.IsNil() {
  149. e := reflect.New(pointerElemReflectValue.Type().Elem()).Elem()
  150. pointerElemReflectValue.Set(e.Addr())
  151. }
  152. // if v, ok := pointerElemReflectValue.Interface().(iUnmarshalValue); ok {
  153. // return v.UnmarshalValue(params)
  154. // }
  155. // Note that it's `pointerElemReflectValue` here not `pointerReflectValue`.
  156. if err, ok = bindVarToReflectValueWithInterfaceCheck(pointerElemReflectValue, paramsInterface); ok {
  157. return err
  158. }
  159. // Retrieve its element, may be struct at last.
  160. pointerElemReflectValue = pointerElemReflectValue.Elem()
  161. }
  162. // paramsMap is the map[string]interface{} type variable for params.
  163. // DO NOT use MapDeep here.
  164. paramsMap := Map(paramsInterface)
  165. if paramsMap == nil {
  166. return gerror.NewCodef(
  167. gcode.CodeInvalidParameter,
  168. `convert params from "%#v" to "map[string]interface{}" failed`,
  169. params,
  170. )
  171. }
  172. // Nothing to be done as the parameters are empty.
  173. if len(paramsMap) == 0 {
  174. return nil
  175. }
  176. // It only performs one converting to the same attribute.
  177. // doneMap is used to check repeated converting, its key is the real attribute name
  178. // of the struct.
  179. doneMap := make(map[string]struct{})
  180. // The key of the attrMap is the attribute name of the struct,
  181. // and the value is its replaced name for later comparison to improve performance.
  182. var (
  183. tempName string
  184. elemFieldType reflect.StructField
  185. elemFieldValue reflect.Value
  186. elemType = pointerElemReflectValue.Type()
  187. attrToCheckNameMap = make(map[string]string)
  188. )
  189. for i := 0; i < pointerElemReflectValue.NumField(); i++ {
  190. elemFieldType = elemType.Field(i)
  191. // Only do converting to public attributes.
  192. if !utils.IsLetterUpper(elemFieldType.Name[0]) {
  193. continue
  194. }
  195. // Maybe it's struct/*struct embedded.
  196. if elemFieldType.Anonymous {
  197. elemFieldValue = pointerElemReflectValue.Field(i)
  198. // Ignore the interface attribute if it's nil.
  199. if elemFieldValue.Kind() == reflect.Interface {
  200. elemFieldValue = elemFieldValue.Elem()
  201. if !elemFieldValue.IsValid() {
  202. continue
  203. }
  204. }
  205. if err = doStruct(paramsMap, elemFieldValue, mapping, priorityTag); err != nil {
  206. return err
  207. }
  208. } else {
  209. tempName = elemFieldType.Name
  210. attrToCheckNameMap[tempName] = utils.RemoveSymbols(tempName)
  211. }
  212. }
  213. if len(attrToCheckNameMap) == 0 {
  214. return nil
  215. }
  216. // The key of the tagMap is the attribute name of the struct,
  217. // and the value is its replaced tag name for later comparison to improve performance.
  218. var (
  219. attrToTagCheckNameMap = make(map[string]string)
  220. priorityTagArray []string
  221. )
  222. if priorityTag != "" {
  223. priorityTagArray = append(utils.SplitAndTrim(priorityTag, ","), StructTagPriority...)
  224. } else {
  225. priorityTagArray = StructTagPriority
  226. }
  227. tagToAttrNameMap, err := gstructs.TagMapName(pointerElemReflectValue, priorityTagArray)
  228. if err != nil {
  229. return err
  230. }
  231. for tagName, attributeName := range tagToAttrNameMap {
  232. // If there's something else in the tag string,
  233. // it uses the first part which is split using char ','.
  234. // Eg:
  235. // orm:"id, priority"
  236. // orm:"name, with:uid=id"
  237. attrToTagCheckNameMap[attributeName] = utils.RemoveSymbols(strings.Split(tagName, ",")[0])
  238. // If tag and attribute values both exist in `paramsMap`,
  239. // it then uses the tag value overwriting the attribute value in `paramsMap`.
  240. if paramsMap[tagName] != nil && paramsMap[attributeName] != nil {
  241. paramsMap[attributeName] = paramsMap[tagName]
  242. }
  243. }
  244. var (
  245. attrName string
  246. checkName string
  247. )
  248. for paramName, paramValue := range paramsMap {
  249. attrName = ""
  250. // It firstly checks the passed mapping rules.
  251. if len(mapping) > 0 {
  252. if passedAttrKey, ok := mapping[paramName]; ok {
  253. attrName = passedAttrKey
  254. }
  255. }
  256. // It secondly checks the predefined tags and matching rules.
  257. if attrName == "" {
  258. // It firstly considers `paramName` as accurate tag name,
  259. // and retrieve attribute name from `tagToAttrNameMap` .
  260. attrName = tagToAttrNameMap[paramName]
  261. if attrName == "" {
  262. checkName = utils.RemoveSymbols(paramName)
  263. // Loop to find the matched attribute name with or without
  264. // string cases and chars like '-'/'_'/'.'/' '.
  265. // Matching the parameters to struct tag names.
  266. // The `attrKey` is the attribute name of the struct.
  267. for attrKey, cmpKey := range attrToTagCheckNameMap {
  268. if strings.EqualFold(checkName, cmpKey) {
  269. attrName = attrKey
  270. break
  271. }
  272. }
  273. }
  274. // Matching the parameters to struct attributes.
  275. if attrName == "" {
  276. for attrKey, cmpKey := range attrToCheckNameMap {
  277. // Eg:
  278. // UserName eq user_name
  279. // User-Name eq username
  280. // username eq userName
  281. // etc.
  282. if strings.EqualFold(checkName, cmpKey) {
  283. attrName = attrKey
  284. break
  285. }
  286. }
  287. }
  288. }
  289. // No matching, it gives up this attribute converting.
  290. if attrName == "" {
  291. continue
  292. }
  293. // If the attribute name is already checked converting, then skip it.
  294. if _, ok = doneMap[attrName]; ok {
  295. continue
  296. }
  297. // Mark it done.
  298. doneMap[attrName] = struct{}{}
  299. if err = bindVarToStructAttr(pointerElemReflectValue, attrName, paramValue, mapping); err != nil {
  300. return err
  301. }
  302. }
  303. return nil
  304. }
  305. // bindVarToStructAttr sets value to struct object attribute by name.
  306. func bindVarToStructAttr(structReflectValue reflect.Value, attrName string, value interface{}, mapping map[string]string) (err error) {
  307. structFieldValue := structReflectValue.FieldByName(attrName)
  308. if !structFieldValue.IsValid() {
  309. return nil
  310. }
  311. // CanSet checks whether attribute is public accessible.
  312. if !structFieldValue.CanSet() {
  313. return nil
  314. }
  315. defer func() {
  316. if exception := recover(); exception != nil {
  317. if err = bindVarToReflectValue(structFieldValue, value, mapping); err != nil {
  318. err = gerror.Wrapf(err, `error binding value to attribute "%s"`, attrName)
  319. }
  320. }
  321. }()
  322. // Directly converting.
  323. if empty.IsNil(value) {
  324. structFieldValue.Set(reflect.Zero(structFieldValue.Type()))
  325. } else {
  326. // Common interface check.
  327. var ok bool
  328. if err, ok = bindVarToReflectValueWithInterfaceCheck(structFieldValue, value); ok {
  329. return err
  330. }
  331. // Default converting.
  332. doConvertWithReflectValueSet(structFieldValue, doConvertInput{
  333. FromValue: value,
  334. ToTypeName: structFieldValue.Type().String(),
  335. ReferValue: structFieldValue,
  336. })
  337. }
  338. return nil
  339. }
  340. // bindVarToReflectValueWithInterfaceCheck does bind using common interfaces checks.
  341. func bindVarToReflectValueWithInterfaceCheck(reflectValue reflect.Value, value interface{}) (err error, ok bool) {
  342. var pointer interface{}
  343. if reflectValue.Kind() != reflect.Ptr && reflectValue.CanAddr() {
  344. reflectValueAddr := reflectValue.Addr()
  345. if reflectValueAddr.IsNil() || !reflectValueAddr.IsValid() {
  346. return nil, false
  347. }
  348. // Not a pointer, but can token address, that makes it can be unmarshalled.
  349. pointer = reflectValue.Addr().Interface()
  350. } else {
  351. if reflectValue.IsNil() || !reflectValue.IsValid() {
  352. return nil, false
  353. }
  354. pointer = reflectValue.Interface()
  355. }
  356. // UnmarshalValue.
  357. if v, ok := pointer.(iUnmarshalValue); ok {
  358. return v.UnmarshalValue(value), ok
  359. }
  360. // UnmarshalText.
  361. if v, ok := pointer.(iUnmarshalText); ok {
  362. var valueBytes []byte
  363. if b, ok := value.([]byte); ok {
  364. valueBytes = b
  365. } else if s, ok := value.(string); ok {
  366. valueBytes = []byte(s)
  367. }
  368. if len(valueBytes) > 0 {
  369. return v.UnmarshalText(valueBytes), ok
  370. }
  371. }
  372. // UnmarshalJSON.
  373. if v, ok := pointer.(iUnmarshalJSON); ok {
  374. var valueBytes []byte
  375. if b, ok := value.([]byte); ok {
  376. valueBytes = b
  377. } else if s, ok := value.(string); ok {
  378. valueBytes = []byte(s)
  379. }
  380. if len(valueBytes) > 0 {
  381. // If it is not a valid JSON string, it then adds char `"` on its both sides to make it is.
  382. if !json.Valid(valueBytes) {
  383. newValueBytes := make([]byte, len(valueBytes)+2)
  384. newValueBytes[0] = '"'
  385. newValueBytes[len(newValueBytes)-1] = '"'
  386. copy(newValueBytes[1:], valueBytes)
  387. valueBytes = newValueBytes
  388. }
  389. return v.UnmarshalJSON(valueBytes), ok
  390. }
  391. }
  392. if v, ok := pointer.(iSet); ok {
  393. v.Set(value)
  394. return nil, ok
  395. }
  396. return nil, false
  397. }
  398. // bindVarToReflectValue sets `value` to reflect value object `structFieldValue`.
  399. func bindVarToReflectValue(structFieldValue reflect.Value, value interface{}, mapping map[string]string) (err error) {
  400. // JSON content converting.
  401. err, ok := doStructWithJsonCheck(value, structFieldValue)
  402. if err != nil {
  403. return err
  404. }
  405. if ok {
  406. return nil
  407. }
  408. kind := structFieldValue.Kind()
  409. // Converting using `Set` interface implements, for some types.
  410. switch kind {
  411. case reflect.Slice, reflect.Array, reflect.Ptr, reflect.Interface:
  412. if !structFieldValue.IsNil() {
  413. if v, ok := structFieldValue.Interface().(iSet); ok {
  414. v.Set(value)
  415. return nil
  416. }
  417. }
  418. }
  419. // Converting using reflection by kind.
  420. switch kind {
  421. case reflect.Map:
  422. return doMapToMap(value, structFieldValue, mapping)
  423. case reflect.Struct:
  424. // Recursively converting for struct attribute.
  425. if err = doStruct(value, structFieldValue, nil, ""); err != nil {
  426. // Note there's reflect conversion mechanism here.
  427. structFieldValue.Set(reflect.ValueOf(value).Convert(structFieldValue.Type()))
  428. }
  429. // Note that the slice element might be type of struct,
  430. // so it uses Struct function doing the converting internally.
  431. case reflect.Slice, reflect.Array:
  432. var (
  433. reflectArray reflect.Value
  434. reflectValue = reflect.ValueOf(value)
  435. )
  436. if reflectValue.Kind() == reflect.Slice || reflectValue.Kind() == reflect.Array {
  437. reflectArray = reflect.MakeSlice(structFieldValue.Type(), reflectValue.Len(), reflectValue.Len())
  438. if reflectValue.Len() > 0 {
  439. var (
  440. elemType = reflectArray.Index(0).Type()
  441. elemTypeName string
  442. converted bool
  443. )
  444. for i := 0; i < reflectValue.Len(); i++ {
  445. converted = false
  446. elemTypeName = elemType.Name()
  447. if elemTypeName == "" {
  448. elemTypeName = elemType.String()
  449. }
  450. var elem reflect.Value
  451. if elemType.Kind() == reflect.Ptr {
  452. elem = reflect.New(elemType.Elem()).Elem()
  453. } else {
  454. elem = reflect.New(elemType).Elem()
  455. }
  456. if elem.Kind() == reflect.Struct {
  457. if err = doStruct(reflectValue.Index(i).Interface(), elem, nil, ""); err == nil {
  458. converted = true
  459. }
  460. }
  461. if !converted {
  462. doConvertWithReflectValueSet(elem, doConvertInput{
  463. FromValue: reflectValue.Index(i).Interface(),
  464. ToTypeName: elemTypeName,
  465. ReferValue: elem,
  466. })
  467. }
  468. if elemType.Kind() == reflect.Ptr {
  469. // Before it sets the `elem` to array, do pointer converting if necessary.
  470. elem = elem.Addr()
  471. }
  472. reflectArray.Index(i).Set(elem)
  473. }
  474. }
  475. } else {
  476. reflectArray = reflect.MakeSlice(structFieldValue.Type(), 1, 1)
  477. var (
  478. elem reflect.Value
  479. elemType = reflectArray.Index(0).Type()
  480. elemTypeName = elemType.Name()
  481. converted bool
  482. )
  483. if elemTypeName == "" {
  484. elemTypeName = elemType.String()
  485. }
  486. if elemType.Kind() == reflect.Ptr {
  487. elem = reflect.New(elemType.Elem()).Elem()
  488. } else {
  489. elem = reflect.New(elemType).Elem()
  490. }
  491. if elem.Kind() == reflect.Struct {
  492. if err = doStruct(value, elem, nil, ""); err == nil {
  493. converted = true
  494. }
  495. }
  496. if !converted {
  497. doConvertWithReflectValueSet(elem, doConvertInput{
  498. FromValue: value,
  499. ToTypeName: elemTypeName,
  500. ReferValue: elem,
  501. })
  502. }
  503. if elemType.Kind() == reflect.Ptr {
  504. // Before it sets the `elem` to array, do pointer converting if necessary.
  505. elem = elem.Addr()
  506. }
  507. reflectArray.Index(0).Set(elem)
  508. }
  509. structFieldValue.Set(reflectArray)
  510. case reflect.Ptr:
  511. if structFieldValue.IsNil() || structFieldValue.IsZero() {
  512. // Nil or empty pointer, it creates a new one.
  513. item := reflect.New(structFieldValue.Type().Elem())
  514. if err, ok = bindVarToReflectValueWithInterfaceCheck(item, value); ok {
  515. structFieldValue.Set(item)
  516. return err
  517. }
  518. elem := item.Elem()
  519. if err = bindVarToReflectValue(elem, value, mapping); err == nil {
  520. structFieldValue.Set(elem.Addr())
  521. }
  522. } else {
  523. // Not empty pointer, it assigns values to it.
  524. return bindVarToReflectValue(structFieldValue.Elem(), value, mapping)
  525. }
  526. // It mainly and specially handles the interface of nil value.
  527. case reflect.Interface:
  528. if value == nil {
  529. // Specially.
  530. structFieldValue.Set(reflect.ValueOf((*interface{})(nil)))
  531. } else {
  532. // Note there's reflect conversion mechanism here.
  533. structFieldValue.Set(reflect.ValueOf(value).Convert(structFieldValue.Type()))
  534. }
  535. default:
  536. defer func() {
  537. if exception := recover(); exception != nil {
  538. err = gerror.NewCodef(
  539. gcode.CodeInternalError,
  540. `cannot convert value "%+v" to type "%s":%+v`,
  541. value,
  542. structFieldValue.Type().String(),
  543. exception,
  544. )
  545. }
  546. }()
  547. // It here uses reflect converting `value` to type of the attribute and assigns
  548. // the result value to the attribute. It might fail and panic if the usual Go
  549. // conversion rules do not allow conversion.
  550. structFieldValue.Set(reflect.ValueOf(value).Convert(structFieldValue.Type()))
  551. }
  552. return nil
  553. }