serialize.go 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186
  1. package rest
  2. import (
  3. "fmt"
  4. "reflect"
  5. "strings"
  6. "git.ali33.ru/fcg-xvii/go-tools/json"
  7. )
  8. type IRestConverter interface {
  9. RestFrom(any) IErrorArgs
  10. }
  11. func parseVal(from, to reflect.Value, fieldName string) IErrorArgs {
  12. if from.Kind() == reflect.Interface {
  13. from = from.Elem()
  14. }
  15. if !from.CanConvert(to.Type()) {
  16. return NewError(
  17. "FieldType",
  18. json.Map{
  19. "field": fieldName,
  20. "expected": to.Type().String(),
  21. "received": from.Type().String(),
  22. },
  23. )
  24. }
  25. to.Set(from.Convert(to.Type()))
  26. return nil
  27. }
  28. func parseType(from, to reflect.Value, fieldName string) IErrorArgs {
  29. from = realValue(from)
  30. to = realValue(to)
  31. switch to.Kind() {
  32. case reflect.Interface:
  33. to.Set(from)
  34. return nil
  35. case reflect.Struct:
  36. return parseStruct(from, to, fieldName)
  37. case reflect.Slice:
  38. return parseSlice(from, to, fieldName)
  39. case reflect.Map:
  40. return parseMap(from, to, fieldName)
  41. default:
  42. return parseVal(from, to, fieldName)
  43. }
  44. }
  45. func realValue(val reflect.Value) reflect.Value {
  46. //log.Println(val.IsNil())
  47. if val.Kind() == reflect.Ptr {
  48. if val.IsNil() {
  49. val.Set(reflect.New(val.Type().Elem()))
  50. }
  51. // check
  52. val = val.Elem()
  53. if val.Kind() == reflect.Ptr {
  54. return realValue(val)
  55. }
  56. }
  57. return val
  58. }
  59. func parseSlice(from, to reflect.Value, fieldName string) IErrorArgs {
  60. if to.IsNil() {
  61. to.Set(reflect.MakeSlice(to.Type(), 0, from.Cap()))
  62. }
  63. eType := to.Type().Elem()
  64. // Перебираем элементы среза, откуда копируем.
  65. for i := 0; i < from.Len(); i++ {
  66. iFieldName := fmt.Sprintf("%v[%v]", fieldName, i)
  67. fromVal := from.Index(i)
  68. toVal := reflect.New(eType).Elem()
  69. if err := parseType(fromVal, toVal.Addr(), iFieldName); err != nil {
  70. return err
  71. }
  72. to.Set(reflect.Append(to, toVal))
  73. }
  74. return nil
  75. }
  76. func parseStruct(from, to reflect.Value, fieldName string) IErrorArgs {
  77. if f, check := to.Interface().(IRestConverter); check {
  78. return f.RestFrom(from.Interface())
  79. }
  80. if to.CanAddr() {
  81. if f, check := to.Addr().Interface().(IRestConverter); check {
  82. return f.RestFrom(from.Interface())
  83. }
  84. }
  85. for i := 0; i < to.NumField(); i++ {
  86. required := false
  87. // устанавливаем тип и указатель поля объекта, куда копируем
  88. fType := to.Type().Field(i)
  89. fVal := to.Field(i)
  90. // проверяем тег, если он есть
  91. tag := fType.Tag.Get("rest")
  92. if len(tag) > 0 {
  93. required = strings.Contains(tag, "required")
  94. }
  95. var rVal reflect.Value
  96. switch from.Kind() {
  97. case reflect.Struct:
  98. if rVal = from.FieldByName(fType.Name); !rVal.IsValid() {
  99. rVal = from.FieldByName(camelToSnake(fType.Name))
  100. }
  101. case reflect.Map:
  102. if rVal = from.MapIndex(reflect.ValueOf(fType.Name)); !rVal.IsValid() {
  103. rVal = from.MapIndex(reflect.ValueOf(camelToSnake(fType.Name)))
  104. }
  105. default:
  106. return NewError(
  107. "FieldType",
  108. json.Map{
  109. "field": fieldName,
  110. "expected": to.Type().String(),
  111. "received": from.Type().String(),
  112. },
  113. )
  114. }
  115. if !rVal.IsValid() {
  116. if required {
  117. return ErrorMessage("RequiredField", fType.Name)
  118. }
  119. continue
  120. }
  121. if rVal.Kind() == reflect.Interface {
  122. rVal = rVal.Elem()
  123. }
  124. iFieldName := fmt.Sprintf("%v.%v", fieldName, fType.Name)
  125. if err := parseType(rVal, fVal.Addr(), iFieldName); err != nil {
  126. return err
  127. }
  128. }
  129. return nil
  130. }
  131. func parseMap(from, to reflect.Value, fieldName string) IErrorArgs {
  132. if to.IsNil() {
  133. to.Set(reflect.MakeMap(to.Type()))
  134. }
  135. switch from.Kind() {
  136. case reflect.Map:
  137. for _, key := range from.MapKeys() {
  138. iFieldName := fmt.Sprintf("%v[%v]", fieldName, key)
  139. fromVal := from.MapIndex(key)
  140. toVal := reflect.New(to.Type().Elem()).Elem()
  141. if err := parseType(fromVal, toVal.Addr(), iFieldName); err != nil {
  142. return err
  143. }
  144. to.SetMapIndex(key, toVal)
  145. }
  146. case reflect.Struct:
  147. for i := 0; i < from.NumField(); i++ {
  148. iFieldName := fmt.Sprintf("%v.%v", fieldName, from.Type().Field(i).Name)
  149. fromVal := from.Field(i)
  150. toVal := reflect.New(to.Type().Elem()).Elem()
  151. if err := parseType(fromVal, toVal.Addr(), iFieldName); err != nil {
  152. return err
  153. }
  154. fName := camelToSnake(from.Type().Field(i).Name)
  155. to.SetMapIndex(reflect.ValueOf(fName), toVal)
  156. }
  157. default:
  158. return NewError(
  159. "FieldType",
  160. json.Map{
  161. "field": fieldName,
  162. "expected": to.Type().String(),
  163. "received": from.Type().String(),
  164. },
  165. )
  166. }
  167. return nil
  168. }
  169. func Serialize(from json.Map, to any) IErrorArgs {
  170. elemTo := reflect.ValueOf(to).Elem()
  171. return parseType(
  172. reflect.ValueOf(&from),
  173. elemTo,
  174. "",
  175. )
  176. }