package dynamicstruct import ( "fmt" "git.zhangdeman.cn/zhangdeman/wrapper" "reflect" "strings" ) type nestedStruct struct { Field string Builder IBuilder Tag string } type builderImpl struct { fields []*fieldConfigImpl nestedStructTable map[string]nestedStruct // 嵌套结构体的定义, 父级路径 => 父级路径下挂接的子路径 maxFieldDeep int // 字段嵌套最大深度 structTagTable map[string]string // 字段路径 => json tag,最高优先级, 没传的时候会使用AddField的tag, 也为空使用手搓json tag } // NewStruct 获取builder实例 // 传入的tag映射表: 字段路径 => json tag,最高优先级, 没传的时候会使用AddField的tag, 也为空使用手搓json tag func NewStruct(structTagTable map[string]string) IBuilder { return &builderImpl{ fields: []*fieldConfigImpl{}, nestedStructTable: make(map[string]nestedStruct), structTagTable: structTagTable, } } // ExtendStruct 基于已有结构体, 生成动态结构体(相当于继承指定的结构体属性) func ExtendStruct(value ...any) IBuilder { return MergeStructs(value...) } // MergeStructs 多个结构体合并成一个动态结构体 func MergeStructs(values ...any) IBuilder { builder := NewStruct(map[string]string{}) for _, value := range values { valueOf := reflect.Indirect(reflect.ValueOf(value)) typeOf := valueOf.Type() for i := 0; i < valueOf.NumField(); i++ { fVal := valueOf.Field(i) fTyp := typeOf.Field(i) builder.(*builderImpl).AddField(fTyp.Name, fTyp.PkgPath, fVal.Interface(), string(fTyp.Tag), fTyp.Anonymous) } } return builder } // IsNestedField 判断是否是嵌套结构体 func (b *builderImpl) parseNestedField(fieldName string) ([]string, bool) { fieldNameArr := strings.Split(strings.Trim(fieldName, "."), ".") return fieldNameArr, len(fieldNameArr) > 1 } // AddField 添加结构体字段 func (b *builderImpl) AddField(name string, pkg string, typ any, tag string, anonymous bool) IBuilder { // 下划线转驼峰, 传入的name实际对应序列化时的json tag // name = wrapper.String(name).SnakeCaseToCamel() if cfgTag, exist := b.structTagTable[name]; exist && len(cfgTag) > 0 { tag = cfgTag } else { if len(tag) == 0 { tag = fmt.Sprintf(`json:"%s"`, name) } } // 判断是否嵌套结构体 fieldNameArr, isNestedField := b.parseNestedField(name) if !isNestedField { // 普通字段 b.addNormalField(name, pkg, typ, tag, anonymous) return b } // 添加嵌套的结构体 b.addNestedField(fieldNameArr, pkg, typ, tag, anonymous) return b } // addNormalField 添加普通无嵌套的字段 func (b *builderImpl) addNormalField(name string, pkg string, typ any, tag string, anonymous bool) { name = wrapper.String(name).SnakeCaseToCamel() if existFieldCfg := b.GetField(name); nil != existFieldCfg { // 说明已存在指定名称字段 // 重复添加, 则会议后面的标签以及类型, 覆盖前面的值 existFieldCfg.SetTag(tag) existFieldCfg.SetType(typ) return } b.fields = append(b.fields, &fieldConfigImpl{ name: name, typ: typ, tag: tag, anonymous: anonymous, pkg: pkg, }) } // addNestedField 添加嵌套字段 func (b *builderImpl) addNestedField(nameArr []string, pkg string, typ any, tag string, anonymous bool) { if len(nameArr) == 1 { // 说明已经是最顶层结构了 b.addNormalField(nameArr[0], pkg, typ, tag, anonymous) return } if len(nameArr) > b.maxFieldDeep { // 设置字段嵌套的最大深度, 由于生成结构体确认深度使用 b.maxFieldDeep = len(nameArr) } for i := len(nameArr) - 1; i > 0; i-- { jsonTag := nameArr[i] fieldName := wrapper.String(jsonTag).SnakeCaseToCamel() parentName := strings.Join(nameArr[:i], ".") parentJsonTag := nameArr[i-1] parentFieldName := wrapper.String(parentJsonTag).SnakeCaseToCamel() fieldTag := fmt.Sprintf(`json:"%s"`, parentJsonTag) if tagCfg, exist := b.structTagTable[parentName]; exist && len(tagCfg) > 0 { fieldTag = tagCfg } if len(parentName) > 0 { if _, exist := b.nestedStructTable[parentName]; !exist { b.nestedStructTable[parentName] = nestedStruct{ Field: parentFieldName, Builder: NewStruct(b.structTagTable), Tag: fieldTag, } } } if i == len(nameArr)-1 { // 最深层此字段, 直接追加到他的父级结构体中即可 b.nestedStructTable[parentName].Builder.AddField(fieldName, pkg, typ, tag, anonymous) continue } } } // RemoveField 根据名称移除结构体字段 func (b *builderImpl) RemoveField(name string) IBuilder { newFieldList := make([]*fieldConfigImpl, 0) for i := range b.fields { if b.fields[i].name == name { continue } newFieldList = append(newFieldList, b.fields[i]) } b.fields = newFieldList return b } // HasField 是否存在指定字段 func (b *builderImpl) HasField(name string) bool { for i := range b.fields { if b.fields[i].name == name { return true } } return false } // GetField 根据名称获取字段配置, 不存在, 返回nil func (b *builderImpl) GetField(name string) IFieldConfig { for i := range b.fields { if b.fields[i].name == name { return b.fields[i] } } return nil } // Build 构建动态结构体 func (b *builderImpl) Build() IDynamicStruct { // 按照嵌套深度, 进行一次回溯处理 for deep := b.maxFieldDeep - 1; deep > 0; deep-- { // 嵌套数据结构 for parentIndex, builderCfg := range b.nestedStructTable { if parentIndex == ArrayRootFlag { continue } parentNameArr := strings.Split(parentIndex, ".") if len(parentNameArr) != deep { // 从深度最深处向上处理 continue } if deep == 1 { // 说明是顶层了 b.AddField(builderCfg.Field, "", builderCfg.Builder.Build().New(), builderCfg.Tag, false) } else { // 处理数组 arrDeep := 0 var newParentNameArr []string for i := len(parentNameArr) - 1; i >= 0; i-- { if parentNameArr[i] != ArraySplit { newParentNameArr = parentNameArr[:i+1] break } // 删除 delete(b.nestedStructTable, strings.Join(parentNameArr[:i+1], ".")) arrDeep++ } if arrDeep > 0 { // 数组嵌套数组配置 val := reflect.ValueOf(builderCfg.Builder.Build().New()).Interface() for i := 0; i < arrDeep; i++ { val = reflect.New(reflect.SliceOf(reflect.TypeOf(val).Elem())).Interface() // 删除数组记录 arrPath := strings.Join(parentNameArr[:len(parentNameArr)-i], ".") delete(b.nestedStructTable, arrPath) } newParentIndex := strings.Join(newParentNameArr, ".") isTopIndex := len(newParentNameArr) == 1 if isTopIndex { // 顶层结构, 数组类型不存在还有其他属性情况, 直接追加字段, 并移除嵌套表里的定义 b.AddField(b.nestedStructTable[newParentIndex].Field, "", val, b.nestedStructTable[newParentIndex].Tag, false) // b.nestedStructTable[newParamIndex].Builder.AddField(b.nestedStructTable[newParamIndex].Field, "", val, b.nestedStructTable[newParamIndex].Tag, false) } else { // 非顶层结构, 再上探一级 newParentName := "" fieldName := "" if len(newParentNameArr) == 0 { // 说明传入的直接就是数组 newParentName = ArrayRootFlag fieldName = ArrayRootFlag b.nestedStructTable[newParentName] = nestedStruct{ Field: fieldName, Builder: NewStruct(b.structTagTable), Tag: "", } b.nestedStructTable[newParentName].Builder.AddField(b.nestedStructTable[newParentName].Field, "", reflect.ValueOf(val).Elem().Interface(), b.nestedStructTable[newParentName].Tag, false) } else { newParentName = strings.Join(newParentNameArr[:len(newParentNameArr)-1], ".") b.nestedStructTable[newParentName].Builder.AddField(b.nestedStructTable[newParentIndex].Field, "", reflect.ValueOf(val).Elem().Interface(), b.nestedStructTable[newParentIndex].Tag, false) } } // 嵌套结构中删除数组字段 delete(b.nestedStructTable, newParentIndex) } else { // 非数组 // (非顶层) 父级结构存在, 将其追加到父级结构中即可, 向前看一步即为父级结构 b.nestedStructTable[strings.Join(parentNameArr[:len(parentNameArr)-1], ".")].Builder.AddField(builderCfg.Field, "", builderCfg.Builder.Build().New(), builderCfg.Tag, false) } } } } if nestedCfg, exist := b.nestedStructTable[ArrayRootFlag]; exist { // 说明是传入的根路径就是数组 return &dynamicStructImpl{ structFields: nil, definition: reflect.TypeOf(nestedCfg.Builder.GetField(ArrayRootFlag).GetType()), } } // 一级字段属性 var structFields []reflect.StructField for _, field := range b.fields { if strings.Contains(field.name, ArraySplit) { // 去除数组路径 continue } structFields = append(structFields, reflect.StructField{ Name: field.name, PkgPath: field.pkg, Type: reflect.TypeOf(field.typ), Tag: reflect.StructTag(field.tag), Anonymous: field.anonymous, }) } return &dynamicStructImpl{ structFields: structFields, definition: reflect.StructOf(structFields), } }