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 5.0 kB

1 year ago
9 months ago
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191
  1. package serder
  2. import (
  3. "bytes"
  4. "encoding/json"
  5. "fmt"
  6. "io"
  7. "reflect"
  8. jsoniter "github.com/json-iterator/go"
  9. "github.com/mitchellh/mapstructure"
  10. )
  11. var unionHandler = UnionHandler{
  12. internallyTagged: make(map[reflect.Type]*anyTypeUnionInternallyTagged),
  13. externallyTagged: make(map[reflect.Type]*anyTypeUnionExternallyTagged),
  14. }
  15. var defaultAPI = func() jsoniter.API {
  16. api := jsoniter.Config{
  17. EscapeHTML: true,
  18. }.Froze()
  19. api.RegisterExtension(&unionHandler)
  20. return api
  21. }()
  22. // 将对象转为JSON字符串。支持TypeUnion。
  23. func ObjectToJSONEx[T any](obj T) ([]byte, error) {
  24. buf := new(bytes.Buffer)
  25. enc := defaultAPI.NewEncoder(buf)
  26. // 这里使用&obj而直接不使用obj的原因是,Encode的形参类型为any,
  27. // 如果T是一个interface类型,将obj传递进去后,内部拿到的类型将会是obj的实际类型,
  28. // 使用&obj,那么内部拿到的将会是*T类型,通过一层一层解引用查找Encoder时,能找到T对应的TypeUnion
  29. err := enc.Encode(&obj)
  30. if err != nil {
  31. return nil, err
  32. }
  33. return buf.Bytes(), nil
  34. }
  35. // 将JSON字符串转为对象。支持TypeUnion。
  36. func JSONToObjectEx[T any](data []byte) (T, error) {
  37. var ret T
  38. dec := defaultAPI.NewDecoder(bytes.NewReader(data))
  39. err := dec.Decode(&ret)
  40. if err != nil {
  41. return ret, err
  42. }
  43. return ret, nil
  44. }
  45. // 将JSON字符串转为对象。支持TypeUnion。
  46. func JSONToObjectExRaw(data []byte, ret any) error {
  47. dec := defaultAPI.NewDecoder(bytes.NewReader(data))
  48. err := dec.Decode(&ret)
  49. if err != nil {
  50. return err
  51. }
  52. return nil
  53. }
  54. // 将JSON字符串转为对象。支持TypeUnion。
  55. //
  56. // 如果发现反序列化后的结果不对,但没有返回错误,可以考虑是JSON字符串有问题,
  57. // 尤其是在反序列化嵌套的TypeUnion时,如果内部的TypeUnion反序列化失败,错误是不会传递出来的(库的缺陷)
  58. func JSONToObjectStreamEx[T any](stream io.Reader) (T, error) {
  59. var ret T
  60. dec := defaultAPI.NewDecoder(stream)
  61. err := dec.Decode(&ret)
  62. if err != nil {
  63. return ret, err
  64. }
  65. return ret, nil
  66. }
  67. // 将对象转为JSON字符串。如果需要支持解析TypeUnion类型,则使用"Ex"结尾的同名函数。
  68. //
  69. // 注:[]byte会被base64编码,如果要JSON内容要给外部解析,那么应该避免使用[]byte。
  70. func ObjectToJSON(obj any) ([]byte, error) {
  71. return json.Marshal(obj)
  72. }
  73. // 将对象转为JSON字符串。如果需要支持解析TypeUnion类型,则使用"Ex"结尾的同名函数。
  74. func ObjectToJSONStream(obj any) io.ReadCloser {
  75. pr, pw := io.Pipe()
  76. enc := json.NewEncoder(pw)
  77. go func() {
  78. err := enc.Encode(obj)
  79. if err != nil && err != io.EOF {
  80. pw.CloseWithError(err)
  81. } else {
  82. pw.Close()
  83. }
  84. }()
  85. return pr
  86. }
  87. // 将JSON字符串转为对象。如果需要支持解析TypeUnion类型,则使用"Ex"结尾的同名函数。
  88. func JSONToObject(data []byte, obj any) error {
  89. return json.Unmarshal(data, obj)
  90. }
  91. // 将JSON字符串转为对象。如果需要支持解析TypeUnion类型,则使用"Ex"结尾的同名函数。
  92. func JSONToObjectStream(str io.Reader, obj any) error {
  93. dec := json.NewDecoder(str)
  94. err := dec.Decode(obj)
  95. if err != io.EOF {
  96. return err
  97. }
  98. return nil
  99. }
  100. type TypeResolver interface {
  101. TypeToString(typ reflect.Type) (string, error)
  102. StringToType(typeStr string) (reflect.Type, error)
  103. }
  104. type MapToObjectOption struct {
  105. NoRegisteredUnionTypes bool // 是否不使用全局注册的UnionType
  106. }
  107. // TODO 使用这个函数来处理TypeUnion的地方都可以直接使用Ex系列的函数
  108. func MapToObject(m map[string]any, obj any, opt ...MapToObjectOption) error {
  109. var op MapToObjectOption
  110. if len(opt) > 0 {
  111. op = opt[0]
  112. }
  113. unionTypeMapping := make(map[reflect.Type]*anyTypeUnionInternallyTagged)
  114. if !op.NoRegisteredUnionTypes {
  115. for _, u := range unionHandler.internallyTagged {
  116. unionTypeMapping[u.Union.UnionType] = u
  117. }
  118. }
  119. convs := []Converter{
  120. func(from reflect.Value, to reflect.Value) (interface{}, error) {
  121. toType := to.Type()
  122. info, ok := unionTypeMapping[toType]
  123. if !ok {
  124. return from.Interface(), nil
  125. }
  126. mp := from.Interface().(map[string]any)
  127. tag, ok := mp[info.TagField]
  128. if !ok {
  129. return nil, fmt.Errorf("converting to %v: no tag field %s in map", toType, info.TagField)
  130. }
  131. tagStr, ok := tag.(string)
  132. if !ok {
  133. return nil, fmt.Errorf("converting to %v: tag field %s value is %v, which is not a string", toType, info.TagField, tag)
  134. }
  135. eleType, ok := info.TagToType[tagStr]
  136. if !ok {
  137. return nil, fmt.Errorf("converting to %v: unknow type tag %s", toType, tagStr)
  138. }
  139. to.Set(reflect.New(eleType).Elem())
  140. return from.Interface(), nil
  141. },
  142. }
  143. return AnyToAny(m, obj, AnyToAnyOption{
  144. Converters: convs,
  145. })
  146. }
  147. func ObjectToMap(obj any) (map[string]any, error) {
  148. mp := make(map[string]any)
  149. dec, err := mapstructure.NewDecoder(&mapstructure.DecoderConfig{
  150. TagName: "json",
  151. Result: &mp,
  152. })
  153. if err != nil {
  154. return nil, err
  155. }
  156. return mp, dec.Decode(obj)
  157. }