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

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127
  1. package serder
  2. import (
  3. "encoding/json"
  4. "fmt"
  5. "reflect"
  6. "time"
  7. mp "github.com/mitchellh/mapstructure"
  8. )
  9. func ObjectToJSON(obj any) ([]byte, error) {
  10. return json.Marshal(obj)
  11. }
  12. func JSONToObject(data []byte, obj any) error {
  13. return json.Unmarshal(data, obj)
  14. }
  15. type TypeResolver interface {
  16. TypeToString(typ reflect.Type) (string, error)
  17. StringToType(typeStr string) (reflect.Type, error)
  18. }
  19. type TypedSerderOption struct {
  20. TypeResolver TypeResolver
  21. TypeFieldName string
  22. }
  23. func parseTimeHook(f reflect.Type, t reflect.Type, data interface{}) (interface{}, error) {
  24. if t != reflect.TypeOf(time.Time{}) {
  25. return data, nil
  26. }
  27. switch f.Kind() {
  28. case reflect.String:
  29. return time.Parse(time.RFC3339, data.(string))
  30. case reflect.Float64:
  31. return time.Unix(0, int64(data.(float64))*int64(time.Millisecond)), nil
  32. case reflect.Int64:
  33. return time.Unix(0, data.(int64)*int64(time.Millisecond)), nil
  34. default:
  35. return data, nil
  36. }
  37. }
  38. func MapToObject(m map[string]any, obj any) error {
  39. config := &mp.DecoderConfig{
  40. TagName: "json",
  41. Squash: true,
  42. WeaklyTypedInput: true,
  43. Result: obj,
  44. DecodeHook: mp.ComposeDecodeHookFunc(parseTimeHook),
  45. }
  46. decoder, err := mp.NewDecoder(config)
  47. if err != nil {
  48. return err
  49. }
  50. return decoder.Decode(m)
  51. }
  52. func ObjectToMap(obj any) (map[string]any, error) {
  53. var retMap map[string]any
  54. config := &mp.DecoderConfig{
  55. TagName: "json",
  56. Squash: true,
  57. WeaklyTypedInput: true,
  58. Result: &retMap,
  59. }
  60. decoder, err := mp.NewDecoder(config)
  61. if err != nil {
  62. return nil, err
  63. }
  64. err = decoder.Decode(obj)
  65. return retMap, err
  66. }
  67. func TypedMapToObject(m map[string]any, opt TypedSerderOption) (any, error) {
  68. typeVal, ok := m[opt.TypeFieldName]
  69. if !ok {
  70. return nil, fmt.Errorf("no type field in the map")
  71. }
  72. typeStr, ok := typeVal.(string)
  73. if !ok {
  74. return nil, fmt.Errorf("type is not a string")
  75. }
  76. typ, err := opt.TypeResolver.StringToType(typeStr)
  77. if err != nil {
  78. return nil, fmt.Errorf("get type from string failed, err: %w", err)
  79. }
  80. val := reflect.New(typ)
  81. valPtr := val.Interface()
  82. err = MapToObject(m, valPtr)
  83. if err != nil {
  84. return nil, err
  85. }
  86. return val.Elem().Interface(), nil
  87. }
  88. func ObjectToTypedMap(obj any, opt TypedSerderOption) (map[string]any, error) {
  89. mp, err := ObjectToMap(obj)
  90. if err != nil {
  91. return nil, err
  92. }
  93. _, ok := mp[opt.TypeFieldName]
  94. if ok {
  95. return nil, fmt.Errorf("object has the same field as the type field")
  96. }
  97. mp[opt.TypeFieldName], err = opt.TypeResolver.TypeToString(reflect.TypeOf(obj))
  98. if err != nil {
  99. return nil, fmt.Errorf("get string from type failed, err: %w", err)
  100. }
  101. return mp, nil
  102. }

公共库

Contributors (1)