serialize.go 6.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244
  1. package rest
  2. import (
  3. "fmt"
  4. "reflect"
  5. "strings"
  6. "git.ali33.ru/fcg-xvii/go-tools/json"
  7. )
  8. // IRestConverter реализует пользовательский пасер из значения, полученного из запроса (см. пример из time.go)
  9. type IRestConverter interface {
  10. // RestFrom реализeт конвертацию из данных запроса в объект
  11. RestFrom(any) IErrorArgs
  12. }
  13. func parseVal(from, to reflect.Value, fieldName string) IErrorArgs {
  14. if from.Kind() == reflect.Interface {
  15. from = from.Elem()
  16. }
  17. if !from.CanConvert(to.Type()) {
  18. return NewError(
  19. "FieldType",
  20. json.Map{
  21. "field": fieldName,
  22. "expected": to.Type().String(),
  23. "received": from.Type().String(),
  24. },
  25. )
  26. }
  27. to.Set(from.Convert(to.Type()))
  28. return nil
  29. }
  30. func parseType(from, to reflect.Value, fieldName string) IErrorArgs {
  31. from = realValue(from)
  32. to = realValue(to)
  33. tn := StructTypeName(to)
  34. cv, check := fieldConverters[tn]
  35. if check {
  36. val, err := cv.Unpack(from.Interface())
  37. if err != nil {
  38. return NewError(
  39. "FieldValue",
  40. json.Map{
  41. "field": fieldName,
  42. "error": err.Error(),
  43. },
  44. )
  45. }
  46. to.Set(reflect.ValueOf(val))
  47. return nil
  48. }
  49. switch to.Kind() {
  50. case reflect.Interface:
  51. if from.Kind() != reflect.Invalid {
  52. to.Set(from)
  53. }
  54. return nil
  55. case reflect.Struct:
  56. return parseStruct(from, to, fieldName)
  57. case reflect.Slice:
  58. return parseSlice(from, to, fieldName)
  59. case reflect.Map:
  60. return parseMap(from, to, fieldName)
  61. default:
  62. return parseVal(from, to, fieldName)
  63. }
  64. }
  65. func realValue(val reflect.Value) reflect.Value {
  66. if val.Kind() == reflect.Ptr || val.Kind() == reflect.Interface {
  67. if val.IsNil() && val.Kind() == reflect.Ptr {
  68. val.Set(reflect.New(val.Type().Elem()))
  69. }
  70. // check
  71. cval := val.Elem()
  72. if cval.Kind() == reflect.Invalid {
  73. return val
  74. }
  75. val = cval
  76. if val.Kind() == reflect.Ptr || val.Kind() == reflect.Interface {
  77. return realValue(cval)
  78. }
  79. }
  80. return val
  81. }
  82. func parseSlice(from, to reflect.Value, fieldName string) IErrorArgs {
  83. if to.IsNil() {
  84. to.Set(reflect.MakeSlice(to.Type(), 0, from.Cap()))
  85. }
  86. eType := to.Type().Elem()
  87. // Перебираем элементы среза, откуда копируем.
  88. for i := 0; i < from.Len(); i++ {
  89. iFieldName := fmt.Sprintf("%v[%v]", fieldName, i)
  90. fromVal := from.Index(i)
  91. toVal := reflect.New(eType).Elem()
  92. if err := parseType(fromVal, toVal.Addr(), iFieldName); err != nil {
  93. return err
  94. }
  95. to.Set(reflect.Append(to, toVal))
  96. }
  97. return nil
  98. }
  99. func parseStruct(from, to reflect.Value, fieldName string) IErrorArgs {
  100. if f, check := to.Interface().(IRestConverter); check {
  101. return f.RestFrom(from.Interface())
  102. }
  103. if to.CanAddr() {
  104. if f, check := to.Addr().Interface().(IRestConverter); check {
  105. return f.RestFrom(from.Interface())
  106. }
  107. }
  108. loop:
  109. for i := 0; i < to.NumField(); i++ {
  110. required := false
  111. // устанавливаем тип и указатель поля объекта, куда копируем
  112. fType := to.Type().Field(i)
  113. fVal := to.Field(i)
  114. // проверяем тег, если он есть
  115. tag := fType.Tag.Get("rest")
  116. if fType.Anonymous && fType.Type.Kind() == reflect.Ptr {
  117. elem := fType.Type.Elem()
  118. if elem.Kind() == reflect.Struct {
  119. if fVal.IsNil() {
  120. fVal.Set(reflect.New(elem))
  121. }
  122. if ierr := parseStruct(from, fVal.Elem(), prefixFieldName(fieldName, fType.Name)); ierr != nil {
  123. return ierr
  124. }
  125. continue loop
  126. }
  127. }
  128. if len(tag) > 0 {
  129. required = strings.Contains(tag, "required")
  130. }
  131. var rVal reflect.Value
  132. switch from.Kind() {
  133. case reflect.Struct:
  134. if rVal = from.FieldByName(fType.Name); !rVal.IsValid() {
  135. rVal = from.FieldByName(fType.Name)
  136. }
  137. case reflect.Map:
  138. /*
  139. log.Println(fType.Name)
  140. if rVal = from.MapIndex(reflect.ValueOf(strings.ToLower(fType.Name))); !rVal.IsValid() {
  141. rVal = from.MapIndex(reflect.ValueOf(fType.Name))
  142. }
  143. */
  144. mapKeys := from.MapKeys()
  145. lowerFTypeName := strings.ToLower(fType.Name)
  146. for _, key := range mapKeys {
  147. lowerKey := strings.ToLower(key.String())
  148. if lowerKey == lowerFTypeName {
  149. rVal = from.MapIndex(key)
  150. break
  151. }
  152. }
  153. if !rVal.IsValid() {
  154. // Если ни один из ключей не совпал, попытаться найти по оригинальному ключу
  155. rVal = from.MapIndex(reflect.ValueOf(fType.Name))
  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. if !rVal.IsValid() {
  168. if required {
  169. return ErrorMessage("RequiredField", fType.Name)
  170. }
  171. continue
  172. }
  173. if rVal.Kind() == reflect.Interface {
  174. rVal = rVal.Elem()
  175. }
  176. var iFieldName string
  177. if fieldName == "" {
  178. iFieldName = fType.Name
  179. } else {
  180. iFieldName = fmt.Sprintf("%v.%v", fieldName, fType.Name)
  181. }
  182. if err := parseType(rVal, fVal.Addr(), iFieldName); err != nil {
  183. return err
  184. }
  185. }
  186. return nil
  187. }
  188. func parseMap(from, to reflect.Value, fieldName string) IErrorArgs {
  189. if to.IsNil() {
  190. to.Set(reflect.MakeMap(to.Type()))
  191. }
  192. switch from.Kind() {
  193. case reflect.Map:
  194. for _, key := range from.MapKeys() {
  195. iFieldName := fmt.Sprintf("%v[%v]", fieldName, key)
  196. fromVal := from.MapIndex(key)
  197. toVal := reflect.New(to.Type().Elem()).Elem()
  198. if err := parseType(fromVal, toVal.Addr(), iFieldName); err != nil {
  199. return err
  200. }
  201. to.SetMapIndex(key, toVal)
  202. }
  203. case reflect.Struct:
  204. for i := 0; i < from.NumField(); i++ {
  205. iFieldName := fmt.Sprintf("%v.%v", fieldName, from.Type().Field(i).Name)
  206. fromVal := from.Field(i)
  207. toVal := reflect.New(to.Type().Elem()).Elem()
  208. if err := parseType(fromVal, toVal.Addr(), iFieldName); err != nil {
  209. return err
  210. }
  211. fName := from.Type().Field(i).Name
  212. to.SetMapIndex(reflect.ValueOf(fName), toVal)
  213. }
  214. default:
  215. return NewError(
  216. "FieldType",
  217. json.Map{
  218. "field": fieldName,
  219. "expected": to.Type().String(),
  220. "received": from.Type().String(),
  221. },
  222. )
  223. }
  224. return nil
  225. }
  226. // Serialize преобразует словарь from в объект произвольного типа
  227. func Serialize(from json.Map, to any) IErrorArgs {
  228. elemTo := reflect.ValueOf(to).Elem()
  229. return parseType(
  230. reflect.ValueOf(&from),
  231. elemTo,
  232. "",
  233. )
  234. }