diff --git a/encoding/gjson/gjson.go b/encoding/gjson/gjson.go index 344fc4235c0..e35a7b026e5 100644 --- a/encoding/gjson/gjson.go +++ b/encoding/gjson/gjson.go @@ -50,6 +50,11 @@ type iMapStrAny interface { MapStrAny() map[string]interface{} } +// iVal is the interface for underlying interface{} retrieving. +type iVal interface { + Val() interface{} +} + // setValue sets `value` to `j` by `pattern`. // Note: // 1. If value is nil and removed is true, means deleting this value; diff --git a/encoding/gjson/gjson_api_new_load.go b/encoding/gjson/gjson_api_new_load.go index 7c6e4cc51f8..367657fa538 100644 --- a/encoding/gjson/gjson_api_new_load.go +++ b/encoding/gjson/gjson_api_new_load.go @@ -67,21 +67,27 @@ func NewWithOptions(data interface{}, options Options) *Json { } } default: - var ( - reflectInfo = utils.OriginValueAndKind(data) - ) + var reflectInfo = utils.OriginValueAndKind(data) switch reflectInfo.OriginKind { case reflect.Slice, reflect.Array: - i := interface{}(nil) - i = gconv.Interfaces(data) + var i interface{} = gconv.Interfaces(data) j = &Json{ p: &i, c: byte(defaultSplitChar), vc: false, } - case reflect.Map, reflect.Struct: - i := interface{}(nil) - i = gconv.MapDeep(data, options.Tags) + case reflect.Map: + var i interface{} = gconv.MapDeep(data, options.Tags) + j = &Json{ + p: &i, + c: byte(defaultSplitChar), + vc: false, + } + case reflect.Struct: + if v, ok := data.(iVal); ok { + return NewWithOptions(v.Val(), options) + } + var i interface{} = gconv.MapDeep(data, options.Tags) j = &Json{ p: &i, c: byte(defaultSplitChar), diff --git a/encoding/gjson/gjson_z_unit_implements_test.go b/encoding/gjson/gjson_z_unit_implements_test.go index 7f94d141180..e0aaec6f2cf 100644 --- a/encoding/gjson/gjson_z_unit_implements_test.go +++ b/encoding/gjson/gjson_z_unit_implements_test.go @@ -28,6 +28,17 @@ func TestJson_UnmarshalJSON(t *testing.T) { t.Assert(j.Get(".").String(), `["a","b","c"]`) t.Assert(j.Get("2").String(), `c`) }) + // Json Array Map + gtest.C(t, func(t *gtest.T) { + var ( + data = []byte(`[{"a":1}, {"b":2}, {"c":3}]`) + j = gjson.New(nil) + err = json.UnmarshalUseNumber(data, j) + ) + t.Assert(err, nil) + t.Assert(j.Get(".").String(), `[{"a":1},{"b":2},{"c":3}]`) + t.Assert(j.Get("2.c").String(), `3`) + }) // Json Map gtest.C(t, func(t *gtest.T) { var ( @@ -77,6 +88,18 @@ func TestJson_UnmarshalValue(t *testing.T) { t.Assert(v.Json.Get(".").String(), `["a","b","c"]`) t.Assert(v.Json.Get("2").String(), `c`) }) + // Json Array Map. + gtest.C(t, func(t *gtest.T) { + var v *V + err := gconv.Struct(g.Map{ + "name": "john", + "json": `[{"a":1},{"b":2},{"c":3}]`, + }, &v) + t.Assert(err, nil) + t.Assert(v.Name, "john") + t.Assert(v.Json.Get(".").String(), `[{"a":1},{"b":2},{"c":3}]`) + t.Assert(v.Json.Get("2.c").String(), `3`) + }) // Map gtest.C(t, func(t *gtest.T) { var v *V diff --git a/encoding/gjson/gjson_z_unit_test.go b/encoding/gjson/gjson_z_unit_test.go index 7317ef53845..c477d95f86f 100644 --- a/encoding/gjson/gjson_z_unit_test.go +++ b/encoding/gjson/gjson_z_unit_test.go @@ -11,20 +11,36 @@ import ( "testing" "github.com/gogf/gf/v2/container/gmap" + "github.com/gogf/gf/v2/container/gvar" "github.com/gogf/gf/v2/encoding/gjson" "github.com/gogf/gf/v2/frame/g" "github.com/gogf/gf/v2/test/gtest" ) func Test_New(t *testing.T) { - data := []byte(`{"n":123456789, "m":{"k":"v"}, "a":[1,2,3]}`) + // New with json map. gtest.C(t, func(t *gtest.T) { + data := []byte(`{"n":123456789, "m":{"k":"v"}, "a":[1,2,3]}`) j := gjson.New(data) t.Assert(j.Get("n").String(), "123456789") t.Assert(j.Get("m").Map(), g.Map{"k": "v"}) t.Assert(j.Get("a").Array(), g.Slice{1, 2, 3}) }) - + // New with json array map. + gtest.C(t, func(t *gtest.T) { + j := gjson.New(`[{"a":1},{"b":2},{"c":3}]`) + t.Assert(j.Get(".").String(), `[{"a":1},{"b":2},{"c":3}]`) + t.Assert(j.Get("2.c").String(), `3`) + }) + // New with gvar. + // https://github.com/gogf/gf/issues/1571 + gtest.C(t, func(t *gtest.T) { + v := gvar.New(`[{"a":1},{"b":2},{"c":3}]`) + j := gjson.New(v) + t.Assert(j.Get(".").String(), `[{"a":1},{"b":2},{"c":3}]`) + t.Assert(j.Get("2.c").String(), `3`) + }) + // New with gmap. gtest.C(t, func(t *gtest.T) { m := gmap.NewAnyAnyMapFrom(g.MapAnyAny{ "k1": "v1", diff --git a/util/gconv/gconv_structs.go b/util/gconv/gconv_structs.go index bb73319fe99..be1322a72ff 100644 --- a/util/gconv/gconv_structs.go +++ b/util/gconv/gconv_structs.go @@ -48,7 +48,7 @@ func doStructs(params interface{}, pointer interface{}, mapping map[string]strin } defer func() { - // Catch the panic, especially the reflect operation panics. + // Catch the panic, especially the reflection operation panics. if exception := recover(); exception != nil { if v, ok := exception.(error); ok && gerror.HasStack(v) { err = v @@ -102,7 +102,7 @@ func doStructs(params interface{}, pointer interface{}, mapping map[string]strin case reflect.Slice, reflect.Array: paramsList = make([]interface{}, paramsRv.Len()) for i := 0; i < paramsRv.Len(); i++ { - paramsList[i] = paramsRv.Index(i) + paramsList[i] = paramsRv.Index(i).Interface() } default: var paramsMaps = Maps(params)