improve package gconv for detailed handling of interface attributes

This commit is contained in:
john
2020-07-13 23:13:50 +08:00
parent 1d87df2afe
commit c135122ca1
5 changed files with 75 additions and 21 deletions

View File

@ -7,7 +7,6 @@
package gconv
import (
"errors"
"github.com/gogf/gf/errors/gerror"
"github.com/gogf/gf/internal/json"
"reflect"
@ -325,7 +324,7 @@ func doMapToMap(params interface{}, pointer interface{}, deep bool, mapping ...m
paramsKind = paramsRv.Kind()
}
if paramsKind != reflect.Map {
return errors.New("params should be type of map")
return gerror.New("params should be type of map")
}
// Empty params map, no need continue.
if paramsRv.Len() == 0 {
@ -343,7 +342,7 @@ func doMapToMap(params interface{}, pointer interface{}, deep bool, mapping ...m
pointerKind = pointerRv.Kind()
}
if pointerKind != reflect.Map {
return errors.New("pointer should be type of *map")
return gerror.New("pointer should be type of *map")
}
defer func() {
// Catch the panic, especially the reflect operation panics.
@ -434,7 +433,7 @@ func doMapToMaps(params interface{}, pointer interface{}, deep bool, mapping ...
paramsKind = paramsRv.Kind()
}
if paramsKind != reflect.Map {
return errors.New("params should be type of map")
return gerror.New("params should be type of map")
}
// Empty params map, no need continue.
if paramsRv.Len() == 0 {
@ -449,7 +448,7 @@ func doMapToMaps(params interface{}, pointer interface{}, deep bool, mapping ...
pointerKind = pointerRv.Kind()
}
if pointerKind != reflect.Map {
return errors.New("pointer should be type of *map/**map")
return gerror.New("pointer should be type of *map/**map")
}
defer func() {
// Catch the panic, especially the reflect operation panics.

View File

@ -7,7 +7,7 @@
package gconv
import (
"fmt"
"github.com/gogf/gf/errors/gerror"
"reflect"
)
@ -19,7 +19,7 @@ func Scan(params interface{}, pointer interface{}, mapping ...map[string]string)
t := reflect.TypeOf(pointer)
k := t.Kind()
if k != reflect.Ptr {
return fmt.Errorf("params should be type of pointer, but got: %v", k)
return gerror.Newf("params should be type of pointer, but got: %v", k)
}
switch t.Elem().Kind() {
case reflect.Array, reflect.Slice:
@ -37,7 +37,7 @@ func ScanDeep(params interface{}, pointer interface{}, mapping ...map[string]str
t := reflect.TypeOf(pointer)
k := t.Kind()
if k != reflect.Ptr {
return fmt.Errorf("params should be type of pointer, but got: %v", k)
return gerror.Newf("params should be type of pointer, but got: %v", k)
}
switch t.Elem().Kind() {
case reflect.Array, reflect.Slice:

View File

@ -7,7 +7,6 @@
package gconv
import (
"errors"
"fmt"
"github.com/gogf/gf/errors/gerror"
"github.com/gogf/gf/internal/empty"
@ -50,10 +49,10 @@ func StructDeep(params interface{}, pointer interface{}, mapping ...map[string]s
// doStruct is the core internal converting function for any data to struct recursively or not.
func doStruct(params interface{}, pointer interface{}, recursive bool, mapping ...map[string]string) (err error) {
if params == nil {
return errors.New("params cannot be nil")
return gerror.New("params cannot be nil")
}
if pointer == nil {
return errors.New("object pointer cannot be nil")
return gerror.New("object pointer cannot be nil")
}
defer func() {
// Catch the panic, especially the reflect operation panics.
@ -65,7 +64,7 @@ func doStruct(params interface{}, pointer interface{}, recursive bool, mapping .
// paramsMap is the map[string]interface{} type variable for params.
paramsMap := MapDeep(params)
if paramsMap == nil {
return fmt.Errorf("invalid params: %v", params)
return gerror.Newf("invalid params: %v", params)
}
// UnmarshalValue.
@ -81,15 +80,23 @@ func doStruct(params interface{}, pointer interface{}, recursive bool, mapping .
if !ok {
rv := reflect.ValueOf(pointer)
if kind := rv.Kind(); kind != reflect.Ptr {
return fmt.Errorf("object pointer should be type of '*struct', but got '%v'", kind)
return gerror.Newf("object pointer should be type of '*struct', but got '%v'", kind)
}
// Using IsNil on reflect.Ptr variable is OK.
if !rv.IsValid() || rv.IsNil() {
return errors.New("object pointer cannot be nil")
return gerror.New("object pointer cannot be nil")
}
elem = rv.Elem()
}
// Check if an invalid interface.
if elem.Kind() == reflect.Interface {
elem = elem.Elem()
if !elem.IsValid() {
return gerror.New("interface type converting is not supported")
}
}
// It automatically creates struct object if necessary.
// For example, if <pointer> is **User, then <elem> is *User, which is a pointer to User.
if elem.Kind() == reflect.Ptr {
@ -360,7 +367,7 @@ func bindVarToReflectValue(structFieldValue reflect.Value, value interface{}, re
default:
defer func() {
if e := recover(); e != nil {
err = errors.New(
err = gerror.New(
fmt.Sprintf(`cannot convert value "%+v" to type "%s"`,
value,
structFieldValue.Type().String(),

View File

@ -7,8 +7,6 @@
package gconv
import (
"errors"
"fmt"
"github.com/gogf/gf/errors/gerror"
"reflect"
)
@ -32,10 +30,10 @@ func StructsDeep(params interface{}, pointer interface{}, mapping ...map[string]
// it will create the struct/pointer internally.
func doStructs(params interface{}, pointer interface{}, deep bool, mapping ...map[string]string) (err error) {
if params == nil {
return errors.New("params cannot be nil")
return gerror.New("params cannot be nil")
}
if pointer == nil {
return errors.New("object pointer cannot be nil")
return gerror.New("object pointer cannot be nil")
}
defer func() {
// Catch the panic, especially the reflect operation panics.
@ -47,7 +45,7 @@ func doStructs(params interface{}, pointer interface{}, deep bool, mapping ...ma
if !ok {
pointerRv = reflect.ValueOf(pointer)
if kind := pointerRv.Kind(); kind != reflect.Ptr {
return fmt.Errorf("pointer should be type of pointer, but got: %v", kind)
return gerror.Newf("pointer should be type of pointer, but got: %v", kind)
}
}
params = Maps(params)
@ -101,6 +99,6 @@ func doStructs(params interface{}, pointer interface{}, deep bool, mapping ...ma
pointerRv.Elem().Set(array)
return nil
default:
return fmt.Errorf("params should be type of slice, but got: %v", reflectKind)
return gerror.Newf("params should be type of slice, but got: %v", reflectKind)
}
}

View File

@ -910,3 +910,53 @@ func Test_Struct_UnmarshalValue(t *testing.T) {
t.AssertNE(err, nil)
})
}
type T struct {
Name string
}
func (t *T) Test() string {
return t.Name
}
type TestInterface interface {
Test() string
}
type TestStruct struct {
TestInterface
}
func Test_Struct_WithInterfaceAttr(t *testing.T) {
// Implemented interface attribute.
gtest.C(t, func(t *gtest.T) {
v1 := TestStruct{
TestInterface: &T{"john"},
}
v2 := g.Map{}
err := gconv.StructDeep(v2, &v1)
t.Assert(err, nil)
t.Assert(v1.Test(), "john")
})
// Implemented interface attribute.
gtest.C(t, func(t *gtest.T) {
v1 := TestStruct{
TestInterface: &T{"john"},
}
v2 := g.Map{
"name": "test",
}
err := gconv.StructDeep(v2, &v1)
t.Assert(err, nil)
t.Assert(v1.Test(), "test")
})
// No implemented interface attribute.
gtest.C(t, func(t *gtest.T) {
v1 := TestStruct{}
v2 := g.Map{
"name": "test",
}
err := gconv.StructDeep(v2, &v1)
t.AssertNE(err, nil)
})
}