From 412b44a98185b2a61500628835afcbd2c115b00e Mon Sep 17 00:00:00 2001 From: Kaming Chan Date: Sat, 7 May 2022 11:00:58 +0800 Subject: [PATCH] Fix: decode nil value in slice decoder (#2102) --- common/structure/structure.go | 14 ++++++++-- common/structure/structure_test.go | 42 ++++++++++++++++++++++++++++++ 2 files changed, 54 insertions(+), 2 deletions(-) diff --git a/common/structure/structure.go b/common/structure/structure.go index 31b0702..081dd36 100644 --- a/common/structure/structure.go +++ b/common/structure/structure.go @@ -159,9 +159,19 @@ func (d *Decoder) decodeSlice(name string, data any, val reflect.Value) error { for valSlice.Len() <= i { valSlice = reflect.Append(valSlice, reflect.Zero(valElemType)) } - currentField := valSlice.Index(i) - fieldName := fmt.Sprintf("%s[%d]", name, i) + if currentData == nil { + // in weakly type mode, null will convert to zero value + if d.option.WeaklyTypedInput { + continue + } + // in non-weakly type mode, null will convert to nil if element's zero value is nil, otherwise return an error + if elemKind := valElemType.Kind(); elemKind == reflect.Map || elemKind == reflect.Slice { + continue + } + return fmt.Errorf("'%s' can not be null", fieldName) + } + currentField := valSlice.Index(i) if err := d.decode(fieldName, currentData, currentField); err != nil { return err } diff --git a/common/structure/structure_test.go b/common/structure/structure_test.go index b3bc52a..9f31d3d 100644 --- a/common/structure/structure_test.go +++ b/common/structure/structure_test.go @@ -137,3 +137,45 @@ func TestStructure_Nest(t *testing.T) { assert.Nil(t, err) assert.Equal(t, s.BazOptional, goal) } + +func TestStructure_SliceNilValue(t *testing.T) { + rawMap := map[string]any{ + "foo": 1, + "bar": []any{"bar", nil}, + } + + goal := &BazSlice{ + Foo: 1, + Bar: []string{"bar", ""}, + } + + s := &BazSlice{} + err := weakTypeDecoder.Decode(rawMap, s) + assert.Nil(t, err) + assert.Equal(t, goal.Bar, s.Bar) + + s = &BazSlice{} + err = decoder.Decode(rawMap, s) + assert.NotNil(t, err) +} + +func TestStructure_SliceNilValueComplex(t *testing.T) { + rawMap := map[string]any{ + "bar": []any{map[string]any{"bar": "foo"}, nil}, + } + + s := &struct { + Bar []map[string]any `test:"bar"` + }{} + + err := decoder.Decode(rawMap, s) + assert.Nil(t, err) + assert.Nil(t, s.Bar[1]) + + ss := &struct { + Bar []Baz `test:"bar"` + }{} + + err = decoder.Decode(rawMap, ss) + assert.NotNil(t, err) +}