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 }