blog_backend_api/utils/reflect.go

271 lines
8.5 KiB
Go

package utils
import (
"log"
"reflect"
"strings"
"github.com/pkg/errors"
)
const (
ErrorTypeError = "error input interface type error"
TagNoExisted = "error remap tag no existed"
)
func reflectMakeNew(t reflect.Type) interface{} {
retptr := reflect.New(t)
sval := retptr.Elem().Interface()
return sval
}
type TagMap map[string]string
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)
num := t.NumField()
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, " ")
}
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)
}
} else {
ret[v[:len(v)-1]] = make(TagMap)
log.Print()
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)
}
}
} else {
continue
}
}
}
}
return ret
}
func SameKind(typ1 reflect.Kind, typ2 reflect.Kind) bool {
switch typ1 {
case reflect.Int:
if typ2 == reflect.Int || typ2 == reflect.Int16 || typ2 == reflect.Int32 || typ2 == reflect.Int64 || typ2 == reflect.Int8 {
return true
}
if typ2 == reflect.Uint || typ2 == reflect.Uint16 || typ2 == reflect.Uint32 || typ2 == reflect.Uint64 || typ2 == reflect.Uint8 {
return true
}
if typ2 == reflect.Float32 || typ2 == reflect.Float64 {
return true
}
case reflect.Int8:
if typ2 == reflect.Int || typ2 == reflect.Int16 || typ2 == reflect.Int32 || typ2 == reflect.Int64 || typ2 == reflect.Int8 {
return true
}
if typ2 == reflect.Uint || typ2 == reflect.Uint16 || typ2 == reflect.Uint32 || typ2 == reflect.Uint64 || typ2 == reflect.Uint8 {
return true
}
if typ2 == reflect.Float32 || typ2 == reflect.Float64 {
return true
}
case reflect.Int16:
if typ2 == reflect.Int || typ2 == reflect.Int16 || typ2 == reflect.Int32 || typ2 == reflect.Int64 || typ2 == reflect.Int8 {
return true
}
if typ2 == reflect.Uint || typ2 == reflect.Uint16 || typ2 == reflect.Uint32 || typ2 == reflect.Uint64 || typ2 == reflect.Uint8 {
return true
}
if typ2 == reflect.Float32 || typ2 == reflect.Float64 {
return true
}
case reflect.Int32:
if typ2 == reflect.Int || typ2 == reflect.Int16 || typ2 == reflect.Int32 || typ2 == reflect.Int64 || typ2 == reflect.Int8 {
return true
}
if typ2 == reflect.Uint || typ2 == reflect.Uint16 || typ2 == reflect.Uint32 || typ2 == reflect.Uint64 || typ2 == reflect.Uint8 {
return true
}
if typ2 == reflect.Float32 || typ2 == reflect.Float64 {
return true
}
case reflect.Int64:
if typ2 == reflect.Int || typ2 == reflect.Int16 || typ2 == reflect.Int32 || typ2 == reflect.Int64 || typ2 == reflect.Int8 {
return true
}
if typ2 == reflect.Uint || typ2 == reflect.Uint16 || typ2 == reflect.Uint32 || typ2 == reflect.Uint64 || typ2 == reflect.Uint8 {
return true
}
if typ2 == reflect.Float32 || typ2 == reflect.Float64 {
return true
}
case reflect.Uint:
if typ2 == reflect.Int || typ2 == reflect.Int16 || typ2 == reflect.Int32 || typ2 == reflect.Int64 || typ2 == reflect.Int8 {
return true
}
if typ2 == reflect.Uint || typ2 == reflect.Uint16 || typ2 == reflect.Uint32 || typ2 == reflect.Uint64 || typ2 == reflect.Uint8 {
return true
}
case reflect.Uint8:
if typ2 == reflect.Int || typ2 == reflect.Int16 || typ2 == reflect.Int32 || typ2 == reflect.Int64 || typ2 == reflect.Int8 {
return true
}
if typ2 == reflect.Uint || typ2 == reflect.Uint16 || typ2 == reflect.Uint32 || typ2 == reflect.Uint64 || typ2 == reflect.Uint8 {
return true
}
case reflect.Uint16:
if typ2 == reflect.Int || typ2 == reflect.Int16 || typ2 == reflect.Int32 || typ2 == reflect.Int64 || typ2 == reflect.Int8 {
return true
}
if typ2 == reflect.Uint || typ2 == reflect.Uint16 || typ2 == reflect.Uint32 || typ2 == reflect.Uint64 || typ2 == reflect.Uint8 {
return true
}
case reflect.Uint32:
if typ2 == reflect.Int || typ2 == reflect.Int16 || typ2 == reflect.Int32 || typ2 == reflect.Int64 || typ2 == reflect.Int8 {
return true
}
if typ2 == reflect.Uint || typ2 == reflect.Uint16 || typ2 == reflect.Uint32 || typ2 == reflect.Uint64 || typ2 == reflect.Uint8 {
return true
}
case reflect.Uint64:
if typ2 == reflect.Int || typ2 == reflect.Int16 || typ2 == reflect.Int32 || typ2 == reflect.Int64 || typ2 == reflect.Int8 {
return true
}
if typ2 == reflect.Uint || typ2 == reflect.Uint16 || typ2 == reflect.Uint32 || typ2 == reflect.Uint64 || typ2 == reflect.Uint8 {
return true
}
case reflect.Float32:
if typ2 == reflect.Float32 || typ2 == reflect.Float64 {
return true
}
case reflect.Float64:
if typ2 == reflect.Float32 || typ2 == reflect.Float64 {
return true
}
default:
return (typ1 == typ2)
}
return false
}
func UnmarshalWithTag(value interface{}, maps map[string]interface{}, tag string) {
if "" == tag {
return
}
valueof := reflect.ValueOf(value)
if !valueof.Elem().CanAddr() {
log.Print("should be addr")
return
}
remap := ReflectTagMap(valueof.Elem().Type())
_, ok := remap[tag]
if !ok {
return
}
for k, v := range maps {
log.Print(k)
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() {
valueof.Elem().FieldByName(filedName).Set(reflect.ValueOf(v).Convert(valueof.Elem().FieldByName(filedName).Type()))
}
}
}
}
}
/*
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())
valueof := reflect.ValueOf(value)
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)
}
remap := ReflectTagMap(opStruct.Type())
_, ok := remap["json"]
if !ok {
return errors.New(TagNoExisted)
}
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()) {
if opStruct.FieldByName(filedName).CanSet() {
opStruct.FieldByName(filedName).Set(reflect.ValueOf(v).Convert(opStruct.FieldByName(filedName).Type()))
}
}
}
}
return nil
}
/*
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)
}
log.Print(remap["json"])
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(filedName, " ", opStruct.FieldByName(filedName).Kind(), reflect.TypeOf(v).Kind().String())
if SameKind(opStruct.FieldByName(filedName).Kind(), reflect.TypeOf(v).Kind()) {
// log.Print(filedName, " can set ", opStruct.FieldByName(filedName).CanSet(), "can addr ", opStruct.FieldByName(filedName).CanAddr())
if opStruct.FieldByName(filedName).CanSet() {
opStruct.FieldByName(filedName).Set(reflect.ValueOf(v).Convert(opStruct.FieldByName(filedName).Type()))
}
}
}
}
return ret.Elem().Interface(), nil
}