package serder import ( "bytes" "encoding/json" "fmt" "io" "reflect" "strings" jsoniter "github.com/json-iterator/go" "github.com/mitchellh/mapstructure" ) var unionHandler = UnionHandler{ internallyTagged: make(map[reflect.Type]*anyTypeUnionInternallyTagged), externallyTagged: make(map[reflect.Type]*anyTypeUnionExternallyTagged), } var defaultAPI = func() jsoniter.API { api := jsoniter.Config{ EscapeHTML: true, }.Froze() api.RegisterExtension(&unionHandler) return api }() // 将对象转为JSON字符串。支持TypeUnion。 func ObjectToJSONEx[T any](obj T) ([]byte, error) { buf := new(bytes.Buffer) enc := defaultAPI.NewEncoder(buf) // 这里使用&obj而直接不使用obj的原因是,Encode的形参类型为any, // 如果T是一个interface类型,将obj传递进去后,内部拿到的类型将会是obj的实际类型, // 使用&obj,那么内部拿到的将会是*T类型,通过一层一层解引用查找Encoder时,能找到T对应的TypeUnion err := enc.Encode(&obj) if err != nil { return nil, err } return buf.Bytes(), nil } // 将JSON字符串转为对象。支持TypeUnion。 func JSONToObjectEx[T any](data []byte) (T, error) { var ret T dec := defaultAPI.NewDecoder(bytes.NewReader(data)) err := dec.Decode(&ret) if err != nil { return ret, err } return ret, nil } // 将JSON字符串转为对象。支持TypeUnion。 func JSONToObjectExRaw(data []byte, ret any) error { dec := defaultAPI.NewDecoder(bytes.NewReader(data)) err := dec.Decode(&ret) if err != nil { return err } return nil } // 将JSON字符串转为对象。支持TypeUnion。 // // 如果发现反序列化后的结果不对,但没有返回错误,可以考虑是JSON字符串有问题, // 尤其是在反序列化嵌套的TypeUnion时,如果内部的TypeUnion反序列化失败,错误是不会传递出来的(库的缺陷) func JSONToObjectStreamEx[T any](stream io.Reader) (T, error) { var ret T dec := defaultAPI.NewDecoder(stream) err := dec.Decode(&ret) if err != nil { return ret, err } return ret, nil } func JSONToObjectStreamExRaw(stream io.Reader, ret any) error { dec := defaultAPI.NewDecoder(stream) err := dec.Decode(ret) if err != nil { return err } return nil } // 将对象转为JSON字符串。如果需要支持解析TypeUnion类型,则使用"Ex"结尾的同名函数。 // // 注:[]byte会被base64编码,如果要JSON内容要给外部解析,那么应该避免使用[]byte。 func ObjectToJSON(obj any) ([]byte, error) { return json.Marshal(obj) } func ObjectToJSONString(obj any) string { marshal, err := json.Marshal(obj) if err != nil { return err.Error() } return string(marshal) } // 将对象转为JSON字符串。如果需要支持解析TypeUnion类型,则使用"Ex"结尾的同名函数。 func ObjectToJSONStream(obj any) io.ReadCloser { pr, pw := io.Pipe() enc := json.NewEncoder(pw) go func() { err := enc.Encode(obj) if err != nil && err != io.EOF { pw.CloseWithError(err) } else { pw.Close() } }() return pr } // 将JSON字符串转为对象。如果需要支持解析TypeUnion类型,则使用"Ex"结尾的同名函数。 func JSONToObject(data []byte, obj any) error { return json.Unmarshal(data, obj) } // 将JSON字符串转为对象。如果需要支持解析TypeUnion类型,则使用"Ex"结尾的同名函数。 func JSONToObjectStream(str io.Reader, obj any) error { dec := json.NewDecoder(str) err := dec.Decode(obj) if err != io.EOF { return err } return nil } type TypeResolver interface { TypeToString(typ reflect.Type) (string, error) StringToType(typeStr string) (reflect.Type, error) } type MapToObjectOption struct { NoRegisteredUnionTypes bool // 是否不使用全局注册的UnionType } // TODO 使用这个函数来处理TypeUnion的地方都可以直接使用Ex系列的函数 func MapToObject(m map[string]any, obj any, opt ...MapToObjectOption) error { var op MapToObjectOption if len(opt) > 0 { op = opt[0] } unionTypeMapping := make(map[reflect.Type]*anyTypeUnionInternallyTagged) if !op.NoRegisteredUnionTypes { for _, u := range unionHandler.internallyTagged { unionTypeMapping[u.Union.UnionType] = u } } convs := []Converter{ func(from reflect.Value, to reflect.Value) (interface{}, error) { toType := to.Type() info, ok := unionTypeMapping[toType] if !ok { return from.Interface(), nil } mp := from.Interface().(map[string]any) tag, ok := mp[info.TagField] if !ok { return nil, fmt.Errorf("converting to %v: no tag field %s in map", toType, info.TagField) } tagStr, ok := tag.(string) if !ok { return nil, fmt.Errorf("converting to %v: tag field %s value is %v, which is not a string", toType, info.TagField, tag) } eleType, ok := info.TagToType[tagStr] if !ok { return nil, fmt.Errorf("converting to %v: unknow type tag %s", toType, tagStr) } to.Set(reflect.New(eleType).Elem()) return from.Interface(), nil }, } return AnyToAny(m, obj, AnyToAnyOption{ Converters: convs, }) } func ObjectToMap(obj any) (map[string]any, error) { mp := make(map[string]any) dec, err := mapstructure.NewDecoder(&mapstructure.DecoderConfig{ TagName: "json", Result: &mp, }) if err != nil { return nil, err } return mp, dec.Decode(obj) } // 1. 尝试解开所有引用 // // 2. nil值将会是空字符串 func ObjectToMapString(obj any) (map[string]string, error) { if obj == nil { return make(map[string]string), nil } v := reflect.ValueOf(obj) for v.Kind() == reflect.Ptr { v = v.Elem() } if !v.IsValid() { return make(map[string]string), nil } if v.Kind() != reflect.Struct { return nil, fmt.Errorf("type %v is not a struct", v.Type()) } mp := make(map[string]string) objectToMapString(v, mp) return mp, nil } func objectToMapString(val reflect.Value, mp map[string]string) { typ := val.Type() for i := 0; i < val.NumField(); i++ { vf := val.Field(i) tf := typ.Field(i) if tf.Anonymous { objectToMapString(vf, mp) continue } fieldName := tf.Name omitEmpty := false jsonTag := tf.Tag.Get("json") if jsonTag != "" { tagParts := strings.Split(jsonTag, ",") fieldName = strings.TrimSpace(tagParts[0]) if len(tagParts) > 1 { for _, tagPart := range tagParts[1:] { tagPart = strings.TrimSpace(tagPart) if tagPart == "omitempty" { omitEmpty = true } } } } for vf.Kind() == reflect.Ptr { vf = vf.Elem() } if !vf.IsValid() { if omitEmpty { continue } mp[fieldName] = "" continue } if vf.IsZero() && omitEmpty { continue } if vf.Kind() == reflect.Array { } mp[fieldName] = fmt.Sprintf("%v", vf) } }