You can not select more than 25 topics Topics must start with a chinese character,a letter or number, can include dashes ('-') and can be up to 35 characters long.

serder.go 6.8 kB

1 year ago
9 months ago
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294
  1. package serder
  2. import (
  3. "bytes"
  4. "encoding/json"
  5. "fmt"
  6. "io"
  7. "reflect"
  8. "strings"
  9. jsoniter "github.com/json-iterator/go"
  10. "github.com/mitchellh/mapstructure"
  11. )
  12. var unionHandler = UnionHandler{
  13. internallyTagged: make(map[reflect.Type]*anyTypeUnionInternallyTagged),
  14. externallyTagged: make(map[reflect.Type]*anyTypeUnionExternallyTagged),
  15. }
  16. var defaultAPI = func() jsoniter.API {
  17. api := jsoniter.Config{
  18. EscapeHTML: true,
  19. }.Froze()
  20. api.RegisterExtension(&unionHandler)
  21. return api
  22. }()
  23. // 将对象转为JSON字符串。支持TypeUnion。
  24. func ObjectToJSONEx[T any](obj T) ([]byte, error) {
  25. buf := new(bytes.Buffer)
  26. enc := defaultAPI.NewEncoder(buf)
  27. // 这里使用&obj而直接不使用obj的原因是,Encode的形参类型为any,
  28. // 如果T是一个interface类型,将obj传递进去后,内部拿到的类型将会是obj的实际类型,
  29. // 使用&obj,那么内部拿到的将会是*T类型,通过一层一层解引用查找Encoder时,能找到T对应的TypeUnion
  30. err := enc.Encode(&obj)
  31. if err != nil {
  32. return nil, err
  33. }
  34. return buf.Bytes(), nil
  35. }
  36. // 将JSON字符串转为对象。支持TypeUnion。
  37. func JSONToObjectEx[T any](data []byte) (T, error) {
  38. var ret T
  39. dec := defaultAPI.NewDecoder(bytes.NewReader(data))
  40. err := dec.Decode(&ret)
  41. if err != nil {
  42. return ret, err
  43. }
  44. return ret, nil
  45. }
  46. // 将JSON字符串转为对象。支持TypeUnion。
  47. func JSONToObjectExRaw(data []byte, ret any) error {
  48. dec := defaultAPI.NewDecoder(bytes.NewReader(data))
  49. err := dec.Decode(&ret)
  50. if err != nil {
  51. return err
  52. }
  53. return nil
  54. }
  55. // 将JSON字符串转为对象。支持TypeUnion。
  56. //
  57. // 如果发现反序列化后的结果不对,但没有返回错误,可以考虑是JSON字符串有问题,
  58. // 尤其是在反序列化嵌套的TypeUnion时,如果内部的TypeUnion反序列化失败,错误是不会传递出来的(库的缺陷)
  59. func JSONToObjectStreamEx[T any](stream io.Reader) (T, error) {
  60. var ret T
  61. dec := defaultAPI.NewDecoder(stream)
  62. err := dec.Decode(&ret)
  63. if err != nil {
  64. return ret, err
  65. }
  66. return ret, nil
  67. }
  68. func JSONToObjectStreamExRaw(stream io.Reader, ret any) error {
  69. dec := defaultAPI.NewDecoder(stream)
  70. err := dec.Decode(ret)
  71. if err != nil {
  72. return err
  73. }
  74. return nil
  75. }
  76. // 将对象转为JSON字符串。如果需要支持解析TypeUnion类型,则使用"Ex"结尾的同名函数。
  77. //
  78. // 注:[]byte会被base64编码,如果要JSON内容要给外部解析,那么应该避免使用[]byte。
  79. func ObjectToJSON(obj any) ([]byte, error) {
  80. return json.Marshal(obj)
  81. }
  82. // 将对象转为JSON字符串。如果需要支持解析TypeUnion类型,则使用"Ex"结尾的同名函数。
  83. func ObjectToJSONStream(obj any) io.ReadCloser {
  84. pr, pw := io.Pipe()
  85. enc := defaultAPI.NewEncoder(pw)
  86. go func() {
  87. err := enc.Encode(obj)
  88. if err != nil && err != io.EOF {
  89. pw.CloseWithError(err)
  90. } else {
  91. pw.Close()
  92. }
  93. }()
  94. return pr
  95. }
  96. func ObjectToJSONStreamEx(obj any) io.ReadCloser {
  97. pr, pw := io.Pipe()
  98. enc := json.NewEncoder(pw)
  99. go func() {
  100. err := enc.Encode(obj)
  101. if err != nil && err != io.EOF {
  102. pw.CloseWithError(err)
  103. } else {
  104. pw.Close()
  105. }
  106. }()
  107. return pr
  108. }
  109. // 将JSON字符串转为对象。如果需要支持解析TypeUnion类型,则使用"Ex"结尾的同名函数。
  110. func JSONToObject(data []byte, obj any) error {
  111. return json.Unmarshal(data, obj)
  112. }
  113. // 将JSON字符串转为对象。如果需要支持解析TypeUnion类型,则使用"Ex"结尾的同名函数。
  114. func JSONToObjectStream(str io.Reader, obj any) error {
  115. dec := json.NewDecoder(str)
  116. err := dec.Decode(obj)
  117. if err != io.EOF {
  118. return err
  119. }
  120. return nil
  121. }
  122. type TypeResolver interface {
  123. TypeToString(typ reflect.Type) (string, error)
  124. StringToType(typeStr string) (reflect.Type, error)
  125. }
  126. type MapToObjectOption struct {
  127. NoRegisteredUnionTypes bool // 是否不使用全局注册的UnionType
  128. }
  129. // TODO 使用这个函数来处理TypeUnion的地方都可以直接使用Ex系列的函数
  130. func MapToObject(m map[string]any, obj any, opt ...MapToObjectOption) error {
  131. var op MapToObjectOption
  132. if len(opt) > 0 {
  133. op = opt[0]
  134. }
  135. unionTypeMapping := make(map[reflect.Type]*anyTypeUnionInternallyTagged)
  136. if !op.NoRegisteredUnionTypes {
  137. for _, u := range unionHandler.internallyTagged {
  138. unionTypeMapping[u.Union.UnionType] = u
  139. }
  140. }
  141. convs := []Converter{
  142. func(from reflect.Value, to reflect.Value) (interface{}, error) {
  143. toType := to.Type()
  144. info, ok := unionTypeMapping[toType]
  145. if !ok {
  146. return from.Interface(), nil
  147. }
  148. mp := from.Interface().(map[string]any)
  149. tag, ok := mp[info.TagField]
  150. if !ok {
  151. return nil, fmt.Errorf("converting to %v: no tag field %s in map", toType, info.TagField)
  152. }
  153. tagStr, ok := tag.(string)
  154. if !ok {
  155. return nil, fmt.Errorf("converting to %v: tag field %s value is %v, which is not a string", toType, info.TagField, tag)
  156. }
  157. eleType, ok := info.TagToType[tagStr]
  158. if !ok {
  159. return nil, fmt.Errorf("converting to %v: unknow type tag %s", toType, tagStr)
  160. }
  161. to.Set(reflect.New(eleType).Elem())
  162. return from.Interface(), nil
  163. },
  164. }
  165. return AnyToAny(m, obj, AnyToAnyOption{
  166. Converters: convs,
  167. })
  168. }
  169. func ObjectToMap(obj any) (map[string]any, error) {
  170. mp := make(map[string]any)
  171. dec, err := mapstructure.NewDecoder(&mapstructure.DecoderConfig{
  172. TagName: "json",
  173. Result: &mp,
  174. })
  175. if err != nil {
  176. return nil, err
  177. }
  178. return mp, dec.Decode(obj)
  179. }
  180. // 1. 尝试解开所有引用
  181. //
  182. // 2. nil值将会是空字符串
  183. func ObjectToMapString(obj any) (map[string]string, error) {
  184. if obj == nil {
  185. return make(map[string]string), nil
  186. }
  187. v := reflect.ValueOf(obj)
  188. for v.Kind() == reflect.Ptr {
  189. v = v.Elem()
  190. }
  191. if !v.IsValid() {
  192. return make(map[string]string), nil
  193. }
  194. if v.Kind() != reflect.Struct {
  195. return nil, fmt.Errorf("type %v is not a struct", v.Type())
  196. }
  197. mp := make(map[string]string)
  198. objectToMapString(v, mp)
  199. return mp, nil
  200. }
  201. func objectToMapString(val reflect.Value, mp map[string]string) {
  202. typ := val.Type()
  203. for i := 0; i < val.NumField(); i++ {
  204. vf := val.Field(i)
  205. tf := typ.Field(i)
  206. if tf.Anonymous {
  207. objectToMapString(vf, mp)
  208. continue
  209. }
  210. fieldName := tf.Name
  211. omitEmpty := false
  212. jsonTag := tf.Tag.Get("json")
  213. if jsonTag != "" {
  214. tagParts := strings.Split(jsonTag, ",")
  215. fieldName = strings.TrimSpace(tagParts[0])
  216. if len(tagParts) > 1 {
  217. for _, tagPart := range tagParts[1:] {
  218. tagPart = strings.TrimSpace(tagPart)
  219. if tagPart == "omitempty" {
  220. omitEmpty = true
  221. }
  222. }
  223. }
  224. }
  225. for vf.Kind() == reflect.Ptr {
  226. vf = vf.Elem()
  227. }
  228. if !vf.IsValid() {
  229. if omitEmpty {
  230. continue
  231. }
  232. mp[fieldName] = ""
  233. continue
  234. }
  235. if vf.IsZero() && omitEmpty {
  236. continue
  237. }
  238. if vf.Kind() == reflect.Array {
  239. }
  240. mp[fieldName] = fmt.Sprintf("%v", vf)
  241. }
  242. }