140 lines
3.5 KiB
Go
140 lines
3.5 KiB
Go
package utils
|
|
|
|
import (
|
|
"fmt"
|
|
"reflect"
|
|
"strings"
|
|
)
|
|
|
|
func MergeJSONObjects(dst, src map[string]interface{}) map[string]interface{} {
|
|
|
|
result := make(map[string]interface{})
|
|
for k, v := range dst {
|
|
result[k] = v
|
|
}
|
|
|
|
for key, value2 := range src {
|
|
value1, exists := result[key]
|
|
|
|
if exists {
|
|
map1Val, map1IsMap := value1.(map[string]interface{})
|
|
map2Val, map2IsMap := value2.(map[string]interface{})
|
|
|
|
if map1IsMap && map2IsMap {
|
|
result[key] = MergeJSONObjects(map1Val, map2Val)
|
|
} else {
|
|
// 覆盖第一个map中的值
|
|
result[key] = value2
|
|
}
|
|
} else {
|
|
// 添加新的键值对
|
|
result[key] = value2
|
|
}
|
|
}
|
|
|
|
return result
|
|
}
|
|
|
|
func StructToMap(in interface{}) (map[string]interface{}, error) {
|
|
out := make(map[string]interface{})
|
|
|
|
v := reflect.ValueOf(in)
|
|
// If it's a pointer, dereference it
|
|
if v.Kind() == reflect.Ptr {
|
|
v = v.Elem()
|
|
}
|
|
|
|
// Check if it's a struct
|
|
if v.Kind() != reflect.Struct {
|
|
return nil, fmt.Errorf("StructToMap only accepts structs or pointers to structs; got %T", v.Interface())
|
|
}
|
|
|
|
t := v.Type() // Get the type of the struct
|
|
for i := 0; i < v.NumField(); i++ {
|
|
// Get the field Value and Type
|
|
fieldV := v.Field(i)
|
|
fieldT := t.Field(i)
|
|
|
|
// Skip unexported fields
|
|
if !fieldT.IsExported() {
|
|
continue
|
|
}
|
|
|
|
// --- Handle JSON Tag ---
|
|
tag := fieldT.Tag.Get("json")
|
|
key := fieldT.Name // Default key is the field name
|
|
omitempty := false
|
|
|
|
if tag != "" {
|
|
parts := strings.Split(tag, ",")
|
|
tagName := parts[0]
|
|
|
|
if tagName == "-" {
|
|
// Skip fields tagged with "-"
|
|
continue
|
|
}
|
|
if tagName != "" {
|
|
key = tagName // Use tag name as key
|
|
}
|
|
|
|
// Check for omitempty option
|
|
for _, part := range parts[1:] {
|
|
if part == "omitempty" {
|
|
omitempty = true
|
|
break
|
|
}
|
|
}
|
|
}
|
|
|
|
// --- Handle omitempty ---
|
|
val := fieldV.Interface()
|
|
if omitempty && fieldV.IsZero() {
|
|
continue // Skip zero-value fields if omitempty is set
|
|
}
|
|
|
|
// --- Handle Nested Structs/Pointers to Structs (Recursion) ---
|
|
// Check for pointer first
|
|
if fieldV.Kind() == reflect.Ptr {
|
|
// If pointer is nil and omitempty is set, it was already skipped
|
|
// If pointer is nil and omitempty is not set, add nil to map
|
|
if fieldV.IsNil() {
|
|
// Only add nil if omitempty is not set (already handled above)
|
|
if !omitempty {
|
|
out[key] = nil
|
|
}
|
|
continue // Move to next field
|
|
}
|
|
// If it points to a struct, dereference and recurse
|
|
if fieldV.Elem().Kind() == reflect.Struct {
|
|
nestedMap, err := StructToMap(fieldV.Interface()) // Pass the pointer
|
|
if err != nil {
|
|
// Decide how to handle nested errors, e.g., log or return
|
|
fmt.Printf("Warning: could not convert nested struct pointer %s: %v\n", fieldT.Name, err)
|
|
out[key] = val // Store original value on error? Or skip?
|
|
} else {
|
|
out[key] = nestedMap
|
|
}
|
|
continue // Move to next field after handling pointer
|
|
}
|
|
// If pointer to non-struct, just get the interface value (handled below)
|
|
val = fieldV.Interface() // Use the actual pointer value
|
|
|
|
} else if fieldV.Kind() == reflect.Struct {
|
|
// If it's a struct (not a pointer), recurse
|
|
nestedMap, err := StructToMap(fieldV.Interface()) // Pass the struct value
|
|
if err != nil {
|
|
fmt.Printf("Warning: could not convert nested struct %s: %v\n", fieldT.Name, err)
|
|
out[key] = val // Store original value on error? Or skip?
|
|
} else {
|
|
out[key] = nestedMap
|
|
}
|
|
continue // Move to next field after handling struct
|
|
}
|
|
|
|
// Assign the value (primitive, slice, map, non-struct pointer, etc.)
|
|
out[key] = val
|
|
}
|
|
|
|
return out, nil
|
|
}
|