1 Star 0 Fork 0

hongzhaomin/hzm-common-go

加入 Gitee
与超过 1200万 开发者一起发现、参与优秀开源项目,私有仓库也完全免费 :)
免费加入
文件
克隆/下载
json.go 6.04 KB
一键复制 编辑 原始数据 按行查看 历史
package toolkit
import (
"encoding/json"
"gitee.com/hongzhaomin/hzm-common-go/logger"
"gitee.com/hongzhaomin/hzm-common-go/strutil"
"reflect"
"strings"
)
// ToJson 该方法结构体可以不写json tag,内部会自动帮我们加
func ToJson(obj any) string {
return ToJson2(obj, true)
}
// ToJson2 该方法会自动识别结构体是否有json的tag,不存在,会自动加上(小驼峰命名)
// omitempty - 表示转json时,是否忽略零值字段
func ToJson2(obj any, omitempty bool) string {
if obj == nil {
return strutil.Empty
}
rv := reflect.Indirect(reflect.ValueOf(obj))
rt := rv.Type()
switch rv.Kind() {
case reflect.Struct:
if NotExistTag(rt, strutil.Json) {
rtNew := addTag4Json(rt, omitempty)
obj = copyValToNewStruct(rtNew, rv)
}
case reflect.Slice, reflect.Array:
rtEle := rt.Elem()
if rtEle.Kind() == reflect.Ptr {
rtEle = rtEle.Elem()
}
if rtEle.Kind() != reflect.Struct {
break
}
if NotExistTag(rtEle, strutil.Json) {
rtEleNew := addTag4Json(rtEle, omitempty)
newObj := make([]any, 0, rv.Len())
for i := 0; i < rv.Len(); i++ {
newEle := copyValToNewStruct(rtEleNew, rv.Index(i))
newObj = append(newObj, newEle)
}
obj = newObj
}
default:
// nothing to do
}
return ToJson3(obj)
}
func copyValToNewStruct(rtNew reflect.Type, rvOld reflect.Value) any {
rtOld := rvOld.Type()
if rtOld.ConvertibleTo(rtNew) {
return rvOld.Convert(rtNew).Interface()
} else {
//rvNewPtr := reflect.New(rtNew)
//CopyProperties(rvOld.Interface(), rvNewPtr.Interface())
rvPtr := reflect.New(rtOld)
rvPtr.Elem().Set(rvOld)
rvNewPtr := reflect.NewAt(rtNew, rvPtr.UnsafePointer())
return rvNewPtr.Interface()
}
}
// ToJson3 对象转json,仅封装异常处理
func ToJson3(obj any) string {
jsonObj, err := json.Marshal(obj)
if err != nil {
logger.Error("ToJson3 转json失败,%v", err)
return strutil.Empty
}
return string(jsonObj)
}
// ToStruct json转对象(泛型)
// 返回泛型结构体指针
func ToStruct[T comparable](jsonStr string) *T {
var bs []byte
if strutil.IsNotBlank(jsonStr) {
bs = []byte(jsonStr)
}
return ToStruct4Bytes[T](bs)
}
// ToStruct4Bytes 字节数组转对象(泛型)
// 返回泛型结构体指针
func ToStruct4Bytes[T comparable](bytes []byte) *T {
rt := reflect.TypeOf((*T)(nil)).Elem()
if rt.Kind() != reflect.Struct {
panic("泛型类型必须为结构体")
}
tPtr := new(T)
if len(bytes) == 0 {
return tPtr
}
err := json.Unmarshal(bytes, tPtr)
if err != nil {
logger.Error("ToStruct4Bytes -> json转结构体失败,%v", err)
}
return tPtr
}
// ToObj json转对象
// 通过obj的指针传回
// 所以obj必须为结构体的指针类型
func ToObj(jsonStr string, obj any) {
if obj == nil || strutil.IsBlank(jsonStr) {
return
}
ToObj4Bytes([]byte(jsonStr), obj)
}
// ToObj4Bytes 字节数组转对象
// 通过obj的指针传回
// 所以obj必须为结构体的指针类型
func ToObj4Bytes(bytes []byte, obj any) {
if obj == nil || bytes == nil {
return
}
rt := reflect.TypeOf(obj)
if rt.Kind() != reflect.Ptr {
// 打印日志,必须是指针类型
return
}
err := json.Unmarshal(bytes, obj)
if err != nil {
logger.Error("ToObj4Bytes 转json失败,%v", err)
}
}
// 结构体字段存在自身类型的结构体不要用这个方法,即结构体的下级属性类型不能存在和外层结构体类型相同,同类型指针也不允许
func addTag4Json(rtStruct reflect.Type, omitempty bool) reflect.Type {
// 前面做了判断
//if rt.Kind() != reflect.Struct {
// panic(errors.New("must be struct kind"))
//}
structName := rtStruct.Name()
// 创建新结构体,添加tag json
numField := rtStruct.NumField()
newStructFields := make([]reflect.StructField, 0, numField)
for i := 0; i < numField; i++ {
field := rtStruct.Field(i)
if strutil.IsNotBlank(field.PkgPath) {
// 字段不可导出
continue
}
rtField := field.Type
isPtr := false
if rtField.Kind() == reflect.Ptr {
rtField = rtField.Elem()
isPtr = true
}
if rtField.Kind() == reflect.Struct {
if !field.Anonymous {
field.Tag = addJsonTag(field.Tag, field.Name, omitempty)
}
// 和自身结构体类型不相同
if rtStruct.PkgPath() == rtField.PkgPath() && rtField.Name() == structName {
logger.Warn("结构体[%s]中字段[%s]的类型为[%s]类型指针,建议自定义添加tag",
structName, field.Name, structName)
goto flag
}
field.Type = addTag4Json(rtField, omitempty)
} else {
field.Tag = addJsonTag(field.Tag, field.Name, omitempty)
if rtField.Kind() == reflect.Slice || rtField.Kind() == reflect.Array {
rtFieldEle := rtField.Elem()
rtFieldEleIsPrt := false
if rtFieldEle.Kind() == reflect.Ptr {
rtFieldEle = rtFieldEle.Elem()
rtFieldEleIsPrt = true
}
if rtFieldEle.Kind() != reflect.Struct {
goto flag
}
// 和自身结构体类型不相同
if rtStruct.PkgPath() == rtField.Elem().PkgPath() && rtField.Elem().Name() == structName {
logger.Warn("结构体[%s]中字段[%s]的切片元素类型为[%s]类型,建议自定义添加tag",
structName, field.Name, structName)
goto flag
}
rtFieldEleStruct := addTag4Json(rtFieldEle, omitempty)
if rtFieldEleIsPrt {
field.Type = reflect.SliceOf(reflect.PointerTo(rtFieldEleStruct))
} else {
field.Type = reflect.SliceOf(rtFieldEleStruct)
}
}
}
if isPtr {
field.Type = reflect.PointerTo(field.Type)
}
flag:
newStructFields = append(newStructFields, field)
}
return reflect.StructOf(newStructFields)
}
func addJsonTag(tag reflect.StructTag, fieldName string, omitempty bool) reflect.StructTag {
// `json:"xxx"`
sb := new(strings.Builder)
sb.WriteString(string(tag))
fieldNameHump := strutil.FirstLetter2Lower(fieldName)
if sb.Len() > 0 {
sb.WriteString(strutil.Space)
}
sb.WriteString(strutil.Json)
sb.WriteString(strutil.Colon)
sb.WriteString(strutil.Quote)
sb.WriteString(fieldNameHump)
if omitempty {
sb.WriteString(strutil.Comma)
sb.WriteString(strutil.Omitempty)
}
sb.WriteString(strutil.Quote)
return reflect.StructTag(sb.String())
}
Loading...
马建仓 AI 助手
尝试更多
代码解读
代码找茬
代码优化
Go
1
https://gitee.com/hongzhaomin/hzm-common-go.git
git@gitee.com:hongzhaomin/hzm-common-go.git
hongzhaomin
hzm-common-go
hzm-common-go
018d78227d0b

搜索帮助