From 0b71bc43a89146695bc681df8f010e0ac9743326 Mon Sep 17 00:00:00 2001 From: Hunk Zhu Date: Tue, 31 Oct 2023 20:02:20 +0800 Subject: [PATCH] fix issue #3099 (#3107) --- util/gconv/gconv_struct.go | 20 +++++--- util/gconv/gconv_z_unit_converter_test.go | 57 +++++++++++++++++++++++ 2 files changed, 71 insertions(+), 6 deletions(-) diff --git a/util/gconv/gconv_struct.go b/util/gconv/gconv_struct.go index f8d58ebe9..2c6433584 100644 --- a/util/gconv/gconv_struct.go +++ b/util/gconv/gconv_struct.go @@ -377,6 +377,20 @@ func bindVarToStructAttr(structReflectValue reflect.Value, attrName string, valu if empty.IsNil(value) { structFieldValue.Set(reflect.Zero(structFieldValue.Type())) } else { + // Try to call custom converter. + // Issue: https://github.com/gogf/gf/issues/3099 + var ( + customConverterInput reflect.Value + ok bool + ) + if customConverterInput, ok = value.(reflect.Value); !ok { + customConverterInput = reflect.ValueOf(value) + } + + if ok, err = callCustomConverter(customConverterInput, structFieldValue); ok || err != nil { + return + } + // Special handling for certain types: // - Overwrite the default type converting logic of stdlib for time.Time/*time.Time. var structFieldTypeName = structFieldValue.Type().String() @@ -399,13 +413,7 @@ func bindVarToStructAttr(structReflectValue reflect.Value, attrName string, valu return } - // Try to call custom converter. - if ok, err := callCustomConverter(reflect.ValueOf(value), structFieldValue); ok { - return err - } - // Common interface check. - var ok bool if err, ok = bindVarToReflectValueWithInterfaceCheck(structFieldValue, value); ok { return err } diff --git a/util/gconv/gconv_z_unit_converter_test.go b/util/gconv/gconv_z_unit_converter_test.go index 04f1d43ef..d9b39b14e 100644 --- a/util/gconv/gconv_z_unit_converter_test.go +++ b/util/gconv/gconv_z_unit_converter_test.go @@ -272,3 +272,60 @@ func TestConverter_CustomBasicType_ToStruct(t *testing.T) { t.Assert(b.S, a) }) } + +// fix: https://github.com/gogf/gf/issues/3099 +func TestConverter_CustomTimeType_ToStruct(t *testing.T) { + type timestamppb struct { + S string + } + type CustomGTime struct { + T *gtime.Time + } + type CustomPbTime struct { + T *timestamppb + } + gtest.C(t, func(t *gtest.T) { + var ( + a = CustomGTime{ + T: gtime.NewFromStrFormat("2023-10-26", "Y-m-d"), + } + b *CustomPbTime + ) + err := gconv.Scan(a, &b) + t.AssertNil(err) + t.AssertNE(b, nil) + t.Assert(b.T.S, "") + }) + + gtest.C(t, func(t *gtest.T) { + err := gconv.RegisterConverter(func(in gtime.Time) (*timestamppb, error) { + return ×tamppb{ + S: in.Local().Format("Y-m-d"), + }, nil + }) + t.AssertNil(err) + err = gconv.RegisterConverter(func(in timestamppb) (*gtime.Time, error) { + return gtime.NewFromStr(in.S), nil + }) + t.AssertNil(err) + }) + gtest.C(t, func(t *gtest.T) { + var ( + a = CustomGTime{ + T: gtime.NewFromStrFormat("2023-10-26", "Y-m-d"), + } + b *CustomPbTime + c *CustomGTime + ) + err := gconv.Scan(a, &b) + t.AssertNil(err) + t.AssertNE(b, nil) + t.AssertNE(b.T, nil) + + err = gconv.Scan(b, &c) + t.AssertNil(err) + t.AssertNE(c, nil) + t.AssertNE(c.T, nil) + t.AssertEQ(a.T.Timestamp(), c.T.Timestamp()) + }) +}