gconv_map.go 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574
  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/internal/empty"
  11. "github.com/gogf/gf/v2/internal/json"
  12. "github.com/gogf/gf/v2/internal/utils"
  13. )
  14. type recursiveType string
  15. const (
  16. recursiveTypeAuto recursiveType = "auto"
  17. recursiveTypeTrue recursiveType = "true"
  18. )
  19. // MapOption specifies the option for map converting.
  20. type MapOption struct {
  21. // Deep marks doing Map function recursively, which means if the attribute of given converting value
  22. // is also a struct/*struct, it automatically calls Map function on this attribute converting it to
  23. // a map[string]interface{} type variable.
  24. Deep bool
  25. // OmitEmpty ignores the attributes that has json `omitempty` tag.
  26. OmitEmpty bool
  27. // Tags specifies the converted map key name by struct tag name.
  28. Tags []string
  29. }
  30. // Map converts any variable `value` to map[string]interface{}. If the parameter `value` is not a
  31. // map/struct/*struct type, then the conversion will fail and returns nil.
  32. //
  33. // If `value` is a struct/*struct object, the second parameter `tags` specifies the most priority
  34. // tags that will be detected, otherwise it detects the tags in order of:
  35. // gconv, json, field name.
  36. func Map(value interface{}, option ...MapOption) map[string]interface{} {
  37. return doMapConvert(value, recursiveTypeAuto, false, option...)
  38. }
  39. // MapDeep does Map function recursively, which means if the attribute of `value`
  40. // is also a struct/*struct, calls Map function on this attribute converting it to
  41. // a map[string]interface{} type variable.
  42. // Deprecated: used Map instead.
  43. func MapDeep(value interface{}, tags ...string) map[string]interface{} {
  44. return doMapConvert(value, recursiveTypeTrue, false, MapOption{
  45. Tags: tags,
  46. })
  47. }
  48. // doMapConvert implements the map converting.
  49. // It automatically checks and converts json string to map if `value` is string/[]byte.
  50. //
  51. // TODO completely implement the recursive converting for all types, especially the map.
  52. func doMapConvert(value interface{}, recursive recursiveType, mustMapReturn bool, option ...MapOption) map[string]interface{} {
  53. if value == nil {
  54. return nil
  55. }
  56. // It redirects to its underlying value if it has implemented interface iVal.
  57. if v, ok := value.(iVal); ok {
  58. value = v.Val()
  59. }
  60. var (
  61. usedOption = getUsedMapOption(option...)
  62. newTags = StructTagPriority
  63. )
  64. switch len(usedOption.Tags) {
  65. case 0:
  66. // No need handling.
  67. case 1:
  68. newTags = append(strings.Split(usedOption.Tags[0], ","), StructTagPriority...)
  69. default:
  70. newTags = append(usedOption.Tags, StructTagPriority...)
  71. }
  72. // Assert the common combination of types, and finally it uses reflection.
  73. dataMap := make(map[string]interface{})
  74. switch r := value.(type) {
  75. case string:
  76. // If it is a JSON string, automatically unmarshal it!
  77. if len(r) > 0 && r[0] == '{' && r[len(r)-1] == '}' {
  78. if err := json.UnmarshalUseNumber([]byte(r), &dataMap); err != nil {
  79. return nil
  80. }
  81. } else {
  82. return nil
  83. }
  84. case []byte:
  85. // If it is a JSON string, automatically unmarshal it!
  86. if len(r) > 0 && r[0] == '{' && r[len(r)-1] == '}' {
  87. if err := json.UnmarshalUseNumber(r, &dataMap); err != nil {
  88. return nil
  89. }
  90. } else {
  91. return nil
  92. }
  93. case map[interface{}]interface{}:
  94. recursiveOption := usedOption
  95. recursiveOption.Tags = newTags
  96. for k, v := range r {
  97. dataMap[String(k)] = doMapConvertForMapOrStructValue(
  98. doMapConvertForMapOrStructValueInput{
  99. IsRoot: false,
  100. Value: v,
  101. RecursiveType: recursive,
  102. RecursiveOption: recursive == recursiveTypeTrue,
  103. Option: recursiveOption,
  104. },
  105. )
  106. }
  107. case map[interface{}]string:
  108. for k, v := range r {
  109. dataMap[String(k)] = v
  110. }
  111. case map[interface{}]int:
  112. for k, v := range r {
  113. dataMap[String(k)] = v
  114. }
  115. case map[interface{}]uint:
  116. for k, v := range r {
  117. dataMap[String(k)] = v
  118. }
  119. case map[interface{}]float32:
  120. for k, v := range r {
  121. dataMap[String(k)] = v
  122. }
  123. case map[interface{}]float64:
  124. for k, v := range r {
  125. dataMap[String(k)] = v
  126. }
  127. case map[string]bool:
  128. for k, v := range r {
  129. dataMap[k] = v
  130. }
  131. case map[string]int:
  132. for k, v := range r {
  133. dataMap[k] = v
  134. }
  135. case map[string]uint:
  136. for k, v := range r {
  137. dataMap[k] = v
  138. }
  139. case map[string]float32:
  140. for k, v := range r {
  141. dataMap[k] = v
  142. }
  143. case map[string]float64:
  144. for k, v := range r {
  145. dataMap[k] = v
  146. }
  147. case map[string]string:
  148. for k, v := range r {
  149. dataMap[k] = v
  150. }
  151. case map[string]interface{}:
  152. if recursive == recursiveTypeTrue {
  153. recursiveOption := usedOption
  154. recursiveOption.Tags = newTags
  155. // A copy of current map.
  156. for k, v := range r {
  157. dataMap[k] = doMapConvertForMapOrStructValue(
  158. doMapConvertForMapOrStructValueInput{
  159. IsRoot: false,
  160. Value: v,
  161. RecursiveType: recursive,
  162. RecursiveOption: recursive == recursiveTypeTrue,
  163. Option: recursiveOption,
  164. },
  165. )
  166. }
  167. } else {
  168. // It returns the map directly without any changing.
  169. return r
  170. }
  171. case map[int]interface{}:
  172. recursiveOption := usedOption
  173. recursiveOption.Tags = newTags
  174. for k, v := range r {
  175. dataMap[String(k)] = doMapConvertForMapOrStructValue(
  176. doMapConvertForMapOrStructValueInput{
  177. IsRoot: false,
  178. Value: v,
  179. RecursiveType: recursive,
  180. RecursiveOption: recursive == recursiveTypeTrue,
  181. Option: recursiveOption,
  182. },
  183. )
  184. }
  185. case map[int]string:
  186. for k, v := range r {
  187. dataMap[String(k)] = v
  188. }
  189. case map[uint]string:
  190. for k, v := range r {
  191. dataMap[String(k)] = v
  192. }
  193. default:
  194. // Not a common type, it then uses reflection for conversion.
  195. var reflectValue reflect.Value
  196. if v, ok := value.(reflect.Value); ok {
  197. reflectValue = v
  198. } else {
  199. reflectValue = reflect.ValueOf(value)
  200. }
  201. reflectKind := reflectValue.Kind()
  202. // If it is a pointer, we should find its real data type.
  203. for reflectKind == reflect.Ptr {
  204. reflectValue = reflectValue.Elem()
  205. reflectKind = reflectValue.Kind()
  206. }
  207. switch reflectKind {
  208. // If `value` is type of array, it converts the value of even number index as its key and
  209. // the value of odd number index as its corresponding value, for example:
  210. // []string{"k1","v1","k2","v2"} => map[string]interface{}{"k1":"v1", "k2":"v2"}
  211. // []string{"k1","v1","k2"} => map[string]interface{}{"k1":"v1", "k2":nil}
  212. case reflect.Slice, reflect.Array:
  213. length := reflectValue.Len()
  214. for i := 0; i < length; i += 2 {
  215. if i+1 < length {
  216. dataMap[String(reflectValue.Index(i).Interface())] = reflectValue.Index(i + 1).Interface()
  217. } else {
  218. dataMap[String(reflectValue.Index(i).Interface())] = nil
  219. }
  220. }
  221. case reflect.Map, reflect.Struct, reflect.Interface:
  222. recursiveOption := usedOption
  223. recursiveOption.Tags = newTags
  224. convertedValue := doMapConvertForMapOrStructValue(
  225. doMapConvertForMapOrStructValueInput{
  226. IsRoot: true,
  227. Value: value,
  228. RecursiveType: recursive,
  229. RecursiveOption: recursive == recursiveTypeTrue,
  230. Option: recursiveOption,
  231. MustMapReturn: mustMapReturn,
  232. },
  233. )
  234. if m, ok := convertedValue.(map[string]interface{}); ok {
  235. return m
  236. }
  237. return nil
  238. default:
  239. return nil
  240. }
  241. }
  242. return dataMap
  243. }
  244. func getUsedMapOption(option ...MapOption) MapOption {
  245. var usedOption MapOption
  246. if len(option) > 0 {
  247. usedOption = option[0]
  248. }
  249. return usedOption
  250. }
  251. type doMapConvertForMapOrStructValueInput struct {
  252. IsRoot bool // It returns directly if it is not root and with no recursive converting.
  253. Value interface{} // Current operation value.
  254. RecursiveType recursiveType // The type from top function entry.
  255. RecursiveOption bool // Whether convert recursively for `current` operation.
  256. Option MapOption // Map converting option.
  257. MustMapReturn bool // Must return map instead of Value when empty.
  258. }
  259. func doMapConvertForMapOrStructValue(in doMapConvertForMapOrStructValueInput) interface{} {
  260. if !in.IsRoot && !in.RecursiveOption {
  261. return in.Value
  262. }
  263. var reflectValue reflect.Value
  264. if v, ok := in.Value.(reflect.Value); ok {
  265. reflectValue = v
  266. in.Value = v.Interface()
  267. } else {
  268. reflectValue = reflect.ValueOf(in.Value)
  269. }
  270. reflectKind := reflectValue.Kind()
  271. // If it is a pointer, we should find its real data type.
  272. for reflectKind == reflect.Ptr {
  273. reflectValue = reflectValue.Elem()
  274. reflectKind = reflectValue.Kind()
  275. }
  276. switch reflectKind {
  277. case reflect.Map:
  278. var (
  279. mapKeys = reflectValue.MapKeys()
  280. dataMap = make(map[string]interface{})
  281. )
  282. for _, k := range mapKeys {
  283. var (
  284. mapKeyValue = reflectValue.MapIndex(k)
  285. mapValue interface{}
  286. )
  287. switch {
  288. case mapKeyValue.IsZero():
  289. if mapKeyValue.IsNil() {
  290. // quick check for nil value.
  291. mapValue = nil
  292. } else {
  293. // in case of:
  294. // exception recovered: reflect: call of reflect.Value.Interface on zero Value
  295. mapValue = reflect.New(mapKeyValue.Type()).Elem().Interface()
  296. }
  297. default:
  298. mapValue = mapKeyValue.Interface()
  299. }
  300. dataMap[String(k.Interface())] = doMapConvertForMapOrStructValue(
  301. doMapConvertForMapOrStructValueInput{
  302. IsRoot: false,
  303. Value: mapValue,
  304. RecursiveType: in.RecursiveType,
  305. RecursiveOption: in.RecursiveType == recursiveTypeTrue,
  306. Option: in.Option,
  307. },
  308. )
  309. }
  310. return dataMap
  311. case reflect.Struct:
  312. var dataMap = make(map[string]interface{})
  313. // Map converting interface check.
  314. if v, ok := in.Value.(iMapStrAny); ok {
  315. // Value copy, in case of concurrent safety.
  316. for mapK, mapV := range v.MapStrAny() {
  317. if in.RecursiveOption {
  318. dataMap[mapK] = doMapConvertForMapOrStructValue(
  319. doMapConvertForMapOrStructValueInput{
  320. IsRoot: false,
  321. Value: mapV,
  322. RecursiveType: in.RecursiveType,
  323. RecursiveOption: in.RecursiveType == recursiveTypeTrue,
  324. Option: in.Option,
  325. },
  326. )
  327. } else {
  328. dataMap[mapK] = mapV
  329. }
  330. }
  331. if len(dataMap) > 0 {
  332. return dataMap
  333. }
  334. }
  335. // Using reflect for converting.
  336. var (
  337. rtField reflect.StructField
  338. rvField reflect.Value
  339. reflectType = reflectValue.Type() // attribute value type.
  340. mapKey = "" // mapKey may be the tag name or the struct attribute name.
  341. )
  342. for i := 0; i < reflectValue.NumField(); i++ {
  343. rtField = reflectType.Field(i)
  344. rvField = reflectValue.Field(i)
  345. // Only convert the public attributes.
  346. fieldName := rtField.Name
  347. if !utils.IsLetterUpper(fieldName[0]) {
  348. continue
  349. }
  350. mapKey = ""
  351. fieldTag := rtField.Tag
  352. for _, tag := range in.Option.Tags {
  353. if mapKey = fieldTag.Get(tag); mapKey != "" {
  354. break
  355. }
  356. }
  357. if mapKey == "" {
  358. mapKey = fieldName
  359. } else {
  360. // Support json tag feature: -, omitempty
  361. mapKey = strings.TrimSpace(mapKey)
  362. if mapKey == "-" {
  363. continue
  364. }
  365. array := strings.Split(mapKey, ",")
  366. if len(array) > 1 {
  367. switch strings.TrimSpace(array[1]) {
  368. case "omitempty":
  369. if in.Option.OmitEmpty && empty.IsEmpty(rvField.Interface()) {
  370. continue
  371. } else {
  372. mapKey = strings.TrimSpace(array[0])
  373. }
  374. default:
  375. mapKey = strings.TrimSpace(array[0])
  376. }
  377. }
  378. if mapKey == "" {
  379. mapKey = fieldName
  380. }
  381. }
  382. if in.RecursiveOption || rtField.Anonymous {
  383. // Do map converting recursively.
  384. var (
  385. rvAttrField = rvField
  386. rvAttrKind = rvField.Kind()
  387. )
  388. if rvAttrKind == reflect.Ptr {
  389. rvAttrField = rvField.Elem()
  390. rvAttrKind = rvAttrField.Kind()
  391. }
  392. switch rvAttrKind {
  393. case reflect.Struct:
  394. // Embedded struct and has no fields, just ignores it.
  395. // Eg: gmeta.Meta
  396. if rvAttrField.Type().NumField() == 0 {
  397. continue
  398. }
  399. var (
  400. hasNoTag = mapKey == fieldName
  401. // DO NOT use rvAttrField.Interface() here,
  402. // as it might be changed from pointer to struct.
  403. rvInterface = rvField.Interface()
  404. )
  405. switch {
  406. case hasNoTag && rtField.Anonymous:
  407. // It means this attribute field has no tag.
  408. // Overwrite the attribute with sub-struct attribute fields.
  409. anonymousValue := doMapConvertForMapOrStructValue(doMapConvertForMapOrStructValueInput{
  410. IsRoot: false,
  411. Value: rvInterface,
  412. RecursiveType: in.RecursiveType,
  413. RecursiveOption: true,
  414. Option: in.Option,
  415. })
  416. if m, ok := anonymousValue.(map[string]interface{}); ok {
  417. for k, v := range m {
  418. dataMap[k] = v
  419. }
  420. } else {
  421. dataMap[mapKey] = rvInterface
  422. }
  423. // It means this attribute field has desired tag.
  424. case !hasNoTag && rtField.Anonymous:
  425. dataMap[mapKey] = doMapConvertForMapOrStructValue(doMapConvertForMapOrStructValueInput{
  426. IsRoot: false,
  427. Value: rvInterface,
  428. RecursiveType: in.RecursiveType,
  429. RecursiveOption: true,
  430. Option: in.Option,
  431. })
  432. default:
  433. dataMap[mapKey] = doMapConvertForMapOrStructValue(doMapConvertForMapOrStructValueInput{
  434. IsRoot: false,
  435. Value: rvInterface,
  436. RecursiveType: in.RecursiveType,
  437. RecursiveOption: in.RecursiveType == recursiveTypeTrue,
  438. Option: in.Option,
  439. })
  440. }
  441. // The struct attribute is type of slice.
  442. case reflect.Array, reflect.Slice:
  443. length := rvAttrField.Len()
  444. if length == 0 {
  445. dataMap[mapKey] = rvAttrField.Interface()
  446. break
  447. }
  448. array := make([]interface{}, length)
  449. for arrayIndex := 0; arrayIndex < length; arrayIndex++ {
  450. array[arrayIndex] = doMapConvertForMapOrStructValue(
  451. doMapConvertForMapOrStructValueInput{
  452. IsRoot: false,
  453. Value: rvAttrField.Index(arrayIndex).Interface(),
  454. RecursiveType: in.RecursiveType,
  455. RecursiveOption: in.RecursiveType == recursiveTypeTrue,
  456. Option: in.Option,
  457. },
  458. )
  459. }
  460. dataMap[mapKey] = array
  461. case reflect.Map:
  462. var (
  463. mapKeys = rvAttrField.MapKeys()
  464. nestedMap = make(map[string]interface{})
  465. )
  466. for _, k := range mapKeys {
  467. nestedMap[String(k.Interface())] = doMapConvertForMapOrStructValue(
  468. doMapConvertForMapOrStructValueInput{
  469. IsRoot: false,
  470. Value: rvAttrField.MapIndex(k).Interface(),
  471. RecursiveType: in.RecursiveType,
  472. RecursiveOption: in.RecursiveType == recursiveTypeTrue,
  473. Option: in.Option,
  474. },
  475. )
  476. }
  477. dataMap[mapKey] = nestedMap
  478. default:
  479. if rvField.IsValid() {
  480. dataMap[mapKey] = reflectValue.Field(i).Interface()
  481. } else {
  482. dataMap[mapKey] = nil
  483. }
  484. }
  485. } else {
  486. // No recursive map value converting
  487. if rvField.IsValid() {
  488. dataMap[mapKey] = reflectValue.Field(i).Interface()
  489. } else {
  490. dataMap[mapKey] = nil
  491. }
  492. }
  493. }
  494. if !in.MustMapReturn && len(dataMap) == 0 {
  495. return in.Value
  496. }
  497. return dataMap
  498. // The given value is type of slice.
  499. case reflect.Array, reflect.Slice:
  500. length := reflectValue.Len()
  501. if length == 0 {
  502. break
  503. }
  504. array := make([]interface{}, reflectValue.Len())
  505. for i := 0; i < length; i++ {
  506. array[i] = doMapConvertForMapOrStructValue(doMapConvertForMapOrStructValueInput{
  507. IsRoot: false,
  508. Value: reflectValue.Index(i).Interface(),
  509. RecursiveType: in.RecursiveType,
  510. RecursiveOption: in.RecursiveType == recursiveTypeTrue,
  511. Option: in.Option,
  512. })
  513. }
  514. return array
  515. }
  516. return in.Value
  517. }
  518. // MapStrStr converts `value` to map[string]string.
  519. // Note that there might be data copy for this map type converting.
  520. func MapStrStr(value interface{}, option ...MapOption) map[string]string {
  521. if r, ok := value.(map[string]string); ok {
  522. return r
  523. }
  524. m := Map(value, option...)
  525. if len(m) > 0 {
  526. vMap := make(map[string]string, len(m))
  527. for k, v := range m {
  528. vMap[k] = String(v)
  529. }
  530. return vMap
  531. }
  532. return nil
  533. }
  534. // MapStrStrDeep converts `value` to map[string]string recursively.
  535. // Note that there might be data copy for this map type converting.
  536. // Deprecated: used MapStrStr instead.
  537. func MapStrStrDeep(value interface{}, tags ...string) map[string]string {
  538. if r, ok := value.(map[string]string); ok {
  539. return r
  540. }
  541. m := MapDeep(value, tags...)
  542. if len(m) > 0 {
  543. vMap := make(map[string]string, len(m))
  544. for k, v := range m {
  545. vMap[k] = String(v)
  546. }
  547. return vMap
  548. }
  549. return nil
  550. }