270 lines
8.4 KiB
Go
270 lines
8.4 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)
|
|
}
|
|
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
|
|
}
|