blog_backend_api/utils/reflect.go

248 lines
7.7 KiB
Go
Raw Normal View History

2021-02-05 17:48:22 +00:00
package utils
2021-02-06 16:45:59 +00:00
import (
"log"
"reflect"
"strings"
2021-02-07 05:14:01 +00:00
"github.com/pkg/errors"
2021-02-06 16:45:59 +00:00
)
2021-02-07 05:14:01 +00:00
const (
ErrorTypeError = "error input interface type error"
TagNoExisted = "error remap tag no existed"
)
2021-02-05 17:48:22 +00:00
2021-02-07 05:14:01 +00:00
func reflectMakeNew(t reflect.Type) interface{} {
2021-02-05 17:48:22 +00:00
retptr := reflect.New(t)
sval := retptr.Elem().Interface()
return sval
}
2021-02-07 05:14:01 +00:00
type TagMap map[string]string
2021-02-05 17:48:22 +00:00
2021-02-07 05:14:01 +00:00
func ReflectTagMap(t reflect.Type) map[string]TagMap {
// log.Print(t.Kind(), " and ", t.Name())
if t.Kind() != reflect.Struct {
return nil
}
ret := make(map[string]TagMap)
2021-02-05 17:48:22 +00:00
num := t.NumField()
2021-02-07 05:14:01 +00:00
for i := 0; i < num; i++ {
sub := strings.Split(string(t.Field(i).Tag), "\"")
for k, v := range sub {
if len(v) > 0 {
if k%2 == 0 {
v = strings.Trim(v, " ")
2021-02-06 16:45:59 +00:00
}
2021-02-07 05:14:01 +00:00
if v[len(v)-1] == ':' {
if _, ok := ret[v[:len(v)-1]]; ok {
if ((k + 1) < len(sub)-1) && ((sub[k+1][len(sub[k+1])-1]) == ':') {
continue
} else {
ret[v[:len(v)-1]][sub[k+1]] = string(t.Field(i).Name)
2021-02-06 16:45:59 +00:00
}
2021-02-07 05:14:01 +00:00
} else {
ret[v[:len(v)-1]] = make(TagMap)
2021-02-06 16:45:59 +00:00
log.Print()
2021-02-07 05:14:01 +00:00
if ((k + 1) < len(sub)-1) && ((sub[k+1][len(sub[k+1])-1]) == ':') {
continue
} else {
ret[v[:len(v)-1]][sub[k+1]] = string(t.Field(i).Name)
2021-02-06 16:45:59 +00:00
}
}
2021-02-07 05:14:01 +00:00
} else {
2021-02-06 16:45:59 +00:00
continue
}
}
2021-02-07 05:14:01 +00:00
2021-02-06 16:45:59 +00:00
}
2021-02-05 17:48:22 +00:00
}
return ret
2021-02-06 16:45:59 +00:00
}
2021-02-07 05:14:01 +00:00
func SameKind(typ1 reflect.Kind, typ2 reflect.Kind) bool {
switch typ1 {
2021-02-06 16:45:59 +00:00
case reflect.Int:
2021-02-07 05:14:01 +00:00
if typ2 == reflect.Int || typ2 == reflect.Int16 || typ2 == reflect.Int32 || typ2 == reflect.Int64 || typ2 == reflect.Int8 {
2021-02-06 16:45:59 +00:00
return true
}
2021-02-07 05:14:01 +00:00
if typ2 == reflect.Uint || typ2 == reflect.Uint16 || typ2 == reflect.Uint32 || typ2 == reflect.Uint64 || typ2 == reflect.Uint8 {
2021-02-06 16:45:59 +00:00
return true
}
case reflect.Int8:
2021-02-07 05:14:01 +00:00
if typ2 == reflect.Int || typ2 == reflect.Int16 || typ2 == reflect.Int32 || typ2 == reflect.Int64 || typ2 == reflect.Int8 {
2021-02-06 16:45:59 +00:00
return true
}
2021-02-07 05:14:01 +00:00
if typ2 == reflect.Uint || typ2 == reflect.Uint16 || typ2 == reflect.Uint32 || typ2 == reflect.Uint64 || typ2 == reflect.Uint8 {
2021-02-06 16:45:59 +00:00
return true
2021-02-07 05:14:01 +00:00
}
2021-02-06 16:45:59 +00:00
case reflect.Int16:
2021-02-07 05:14:01 +00:00
if typ2 == reflect.Int || typ2 == reflect.Int16 || typ2 == reflect.Int32 || typ2 == reflect.Int64 || typ2 == reflect.Int8 {
2021-02-06 16:45:59 +00:00
return true
}
2021-02-07 05:14:01 +00:00
if typ2 == reflect.Uint || typ2 == reflect.Uint16 || typ2 == reflect.Uint32 || typ2 == reflect.Uint64 || typ2 == reflect.Uint8 {
2021-02-06 16:45:59 +00:00
return true
}
case reflect.Int32:
2021-02-07 05:14:01 +00:00
if typ2 == reflect.Int || typ2 == reflect.Int16 || typ2 == reflect.Int32 || typ2 == reflect.Int64 || typ2 == reflect.Int8 {
2021-02-06 16:45:59 +00:00
return true
}
2021-02-07 05:14:01 +00:00
if typ2 == reflect.Uint || typ2 == reflect.Uint16 || typ2 == reflect.Uint32 || typ2 == reflect.Uint64 || typ2 == reflect.Uint8 {
2021-02-06 16:45:59 +00:00
return true
2021-02-07 05:14:01 +00:00
}
2021-02-06 16:45:59 +00:00
case reflect.Uint:
2021-02-07 05:14:01 +00:00
if typ2 == reflect.Int || typ2 == reflect.Int16 || typ2 == reflect.Int32 || typ2 == reflect.Int64 || typ2 == reflect.Int8 {
2021-02-06 16:45:59 +00:00
return true
}
2021-02-07 05:14:01 +00:00
if typ2 == reflect.Uint || typ2 == reflect.Uint16 || typ2 == reflect.Uint32 || typ2 == reflect.Uint64 || typ2 == reflect.Uint8 {
2021-02-06 16:45:59 +00:00
return true
}
case reflect.Uint8:
2021-02-07 05:14:01 +00:00
if typ2 == reflect.Int || typ2 == reflect.Int16 || typ2 == reflect.Int32 || typ2 == reflect.Int64 || typ2 == reflect.Int8 {
2021-02-06 16:45:59 +00:00
return true
}
2021-02-07 05:14:01 +00:00
if typ2 == reflect.Uint || typ2 == reflect.Uint16 || typ2 == reflect.Uint32 || typ2 == reflect.Uint64 || typ2 == reflect.Uint8 {
2021-02-06 16:45:59 +00:00
return true
}
case reflect.Uint16:
2021-02-07 05:14:01 +00:00
if typ2 == reflect.Int || typ2 == reflect.Int16 || typ2 == reflect.Int32 || typ2 == reflect.Int64 || typ2 == reflect.Int8 {
2021-02-06 16:45:59 +00:00
return true
}
2021-02-07 05:14:01 +00:00
if typ2 == reflect.Uint || typ2 == reflect.Uint16 || typ2 == reflect.Uint32 || typ2 == reflect.Uint64 || typ2 == reflect.Uint8 {
2021-02-06 16:45:59 +00:00
return true
2021-02-07 05:14:01 +00:00
}
2021-02-06 16:45:59 +00:00
case reflect.Uint32:
2021-02-07 05:14:01 +00:00
if typ2 == reflect.Int || typ2 == reflect.Int16 || typ2 == reflect.Int32 || typ2 == reflect.Int64 || typ2 == reflect.Int8 {
2021-02-06 16:45:59 +00:00
return true
}
2021-02-07 05:14:01 +00:00
if typ2 == reflect.Uint || typ2 == reflect.Uint16 || typ2 == reflect.Uint32 || typ2 == reflect.Uint64 || typ2 == reflect.Uint8 {
2021-02-06 16:45:59 +00:00
return true
}
case reflect.Uint64:
2021-02-07 05:14:01 +00:00
if typ2 == reflect.Int || typ2 == reflect.Int16 || typ2 == reflect.Int32 || typ2 == reflect.Int64 || typ2 == reflect.Int8 {
2021-02-06 16:45:59 +00:00
return true
}
2021-02-07 05:14:01 +00:00
if typ2 == reflect.Uint || typ2 == reflect.Uint16 || typ2 == reflect.Uint32 || typ2 == reflect.Uint64 || typ2 == reflect.Uint8 {
2021-02-06 16:45:59 +00:00
return true
2021-02-07 05:14:01 +00:00
}
2021-02-06 16:45:59 +00:00
case reflect.Float32:
2021-02-07 05:14:01 +00:00
if typ2 == reflect.Float32 || typ2 == reflect.Float64 {
2021-02-06 16:45:59 +00:00
return true
}
case reflect.Float64:
2021-02-07 05:14:01 +00:00
if typ2 == reflect.Float32 || typ2 == reflect.Float64 {
2021-02-06 16:45:59 +00:00
return true
}
default:
2021-02-07 05:14:01 +00:00
return (typ1 == typ2)
2021-02-06 16:45:59 +00:00
}
return false
}
2021-02-07 05:14:01 +00:00
func UnmarshalWithTag(value interface{}, maps map[string]interface{}, tag string) {
if "" == tag {
2021-02-06 16:48:29 +00:00
return
}
valueof := reflect.ValueOf(value)
2021-02-07 05:14:01 +00:00
if !valueof.Elem().CanAddr() {
2021-02-06 16:48:29 +00:00
log.Print("should be addr")
return
}
remap := ReflectTagMap(valueof.Elem().Type())
2021-02-07 05:14:01 +00:00
_, ok := remap[tag]
if !ok {
return
2021-02-06 16:48:29 +00:00
}
2021-02-07 05:14:01 +00:00
for k, v := range maps {
2021-02-06 16:48:29 +00:00
log.Print(k)
2021-02-07 05:14:01 +00:00
if filedName, ok := remap["json"][k]; ok {
log.Print(valueof.Elem().FieldByName(filedName).Kind(), reflect.TypeOf(v).Kind().String())
if SameKind(valueof.Elem().FieldByName(filedName).Kind(), reflect.TypeOf(v).Kind()) {
if valueof.Elem().FieldByName(filedName).CanSet() {
2021-02-06 16:48:29 +00:00
valueof.Elem().FieldByName(filedName).Set(reflect.ValueOf(v).Convert(valueof.Elem().FieldByName(filedName).Type()))
}
}
}
}
}
2021-02-07 05:14:01 +00:00
/*
an generaly unmarshal function implement
accept only pointer to struct or pointer to interface contains struct
*/
func UnmarshalJson2Struct(value interface{}, maps map[string]interface{}) error {
log.Print("UnmarshalJson kind is ", reflect.ValueOf(value).Kind())
log.Print("UnmarshalJson kind1 is ", reflect.ValueOf(value).Elem().Kind())
// log.Print("UnmarshalJson kind2 is ", reflect.ValueOf(value).Elem().Elem().Kind())
2021-02-06 16:45:59 +00:00
valueof := reflect.ValueOf(value)
2021-02-07 05:14:01 +00:00
var opStruct reflect.Value
if valueof.Kind() == reflect.Ptr {
// if it is ptr to interface,the interface must contains a struct type
if valueof.Elem().Kind() == reflect.Interface {
if valueof.Elem().Elem().Kind() == reflect.Struct {
opStruct = valueof.Elem().Elem()
} else {
return errors.New(ErrorTypeError)
}
} else if valueof.Elem().Kind() == reflect.Struct {
// simply it is ptr to struct
opStruct = valueof.Elem()
} else {
return errors.New(ErrorTypeError)
}
} else {
return errors.New(ErrorTypeError)
2021-02-06 16:45:59 +00:00
}
2021-02-07 05:14:01 +00:00
remap := ReflectTagMap(opStruct.Type())
_, ok := remap["json"]
if !ok {
return errors.New(TagNoExisted)
2021-02-06 16:45:59 +00:00
}
2021-02-07 05:14:01 +00:00
for k, v := range maps {
2021-02-06 16:45:59 +00:00
log.Print(k)
2021-02-07 05:14:01 +00:00
if filedName, ok := remap["json"][k]; ok {
log.Print(opStruct.FieldByName(filedName).Kind(), reflect.TypeOf(v).Kind().String())
if SameKind(opStruct.FieldByName(filedName).Kind(), reflect.TypeOf(v).Kind()) {
if opStruct.FieldByName(filedName).CanSet() {
opStruct.FieldByName(filedName).Set(reflect.ValueOf(v).Convert(opStruct.FieldByName(filedName).Type()))
2021-02-06 16:45:59 +00:00
}
}
}
}
2021-02-07 05:14:01 +00:00
return nil
2021-02-06 16:45:59 +00:00
}
2021-02-07 05:14:01 +00:00
/*
an generaly unmarshal function implement
accept only pointer to struct or pointer to interface contains struct
*/
func UnmarshalJson2StructGen(t reflect.Type, maps map[string]interface{}) (interface{}, error) {
if t.Kind() != reflect.Struct {
return nil, errors.New(ErrorTypeError)
}
remap := ReflectTagMap(t)
_, ok := remap["json"]
if !ok {
return nil, errors.New(TagNoExisted)
}
ret := reflect.New(t)
// log.Print(ret.Kind())
opStruct := ret.Elem()
// log.Print(opStruct.Kind())
for k, v := range maps {
log.Print(k)
if filedName, ok := remap["json"][k]; ok {
// log.Print(opStruct.FieldByName(filedName).Kind(), reflect.TypeOf(v).Kind().String())
if SameKind(opStruct.FieldByName(filedName).Kind(), reflect.TypeOf(v).Kind()) {
// log.Print(opStruct.FieldByName(filedName).CanAddr(), opStruct.FieldByName(filedName).CanSet())
if opStruct.FieldByName(filedName).CanSet() {
opStruct.FieldByName(filedName).Set(reflect.ValueOf(v).Convert(opStruct.FieldByName(filedName).Type()))
}
}
}
}
return ret.Elem().Interface(), nil
}