diff --git a/core/mapping/jsonunmarshaler.go b/core/mapping/jsonunmarshaler.go index 540581a3..f832224d 100644 --- a/core/mapping/jsonunmarshaler.go +++ b/core/mapping/jsonunmarshaler.go @@ -34,7 +34,7 @@ func getJsonUnmarshaler(opts ...UnmarshalOption) *Unmarshaler { } func unmarshalJsonBytes(content []byte, v interface{}, unmarshaler *Unmarshaler) error { - var m map[string]interface{} + var m interface{} if err := jsonx.Unmarshal(content, &m); err != nil { return err } @@ -43,7 +43,7 @@ func unmarshalJsonBytes(content []byte, v interface{}, unmarshaler *Unmarshaler) } func unmarshalJsonReader(reader io.Reader, v interface{}, unmarshaler *Unmarshaler) error { - var m map[string]interface{} + var m interface{} if err := jsonx.UnmarshalFromReader(reader, &m); err != nil { return err } diff --git a/core/mapping/jsonunmarshaler_test.go b/core/mapping/jsonunmarshaler_test.go index 28615d31..05af99c9 100644 --- a/core/mapping/jsonunmarshaler_test.go +++ b/core/mapping/jsonunmarshaler_test.go @@ -856,8 +856,7 @@ func TestUnmarshalBytesError(t *testing.T) { } err := UnmarshalJsonBytes([]byte(payload), &v) - assert.NotNil(t, err) - assert.True(t, strings.Contains(err.Error(), payload)) + assert.Equal(t, errTypeMismatch, err) } func TestUnmarshalReaderError(t *testing.T) { @@ -867,9 +866,7 @@ func TestUnmarshalReaderError(t *testing.T) { Any string } - err := UnmarshalJsonReader(reader, &v) - assert.NotNil(t, err) - assert.True(t, strings.Contains(err.Error(), payload)) + assert.Equal(t, errTypeMismatch, UnmarshalJsonReader(reader, &v)) } func TestUnmarshalMap(t *testing.T) { @@ -920,3 +917,16 @@ func TestUnmarshalMap(t *testing.T) { assert.Equal(t, "foo", v.Any) }) } + +func TestUnmarshalJsonArray(t *testing.T) { + var v []struct { + Name string `json:"name"` + Age int `json:"age"` + } + + body := `[{"name":"kevin", "age": 18}]` + assert.NoError(t, UnmarshalJsonBytes([]byte(body), &v)) + assert.Equal(t, 1, len(v)) + assert.Equal(t, "kevin", v[0].Name) + assert.Equal(t, 18, v[0].Age) +} diff --git a/core/mapping/unmarshaler.go b/core/mapping/unmarshaler.go index 767b2903..e6c7425e 100644 --- a/core/mapping/unmarshaler.go +++ b/core/mapping/unmarshaler.go @@ -71,8 +71,29 @@ func UnmarshalKey(m map[string]interface{}, v interface{}) error { } // Unmarshal unmarshals m into v. -func (u *Unmarshaler) Unmarshal(m map[string]interface{}, v interface{}) error { - return u.UnmarshalValuer(mapValuer(m), v) +func (u *Unmarshaler) Unmarshal(i interface{}, v interface{}) error { + valueType := reflect.TypeOf(v) + if valueType.Kind() != reflect.Ptr { + return errValueNotSettable + } + + elemType := valueType.Elem() + switch iv := i.(type) { + case map[string]interface{}: + if elemType.Kind() != reflect.Struct { + return errTypeMismatch + } + + return u.UnmarshalValuer(mapValuer(iv), v) + case []interface{}: + if elemType.Kind() != reflect.Slice { + return errTypeMismatch + } + + return u.fillSlice(elemType, reflect.ValueOf(v).Elem(), iv) + default: + return errUnsupportedType + } } // UnmarshalValuer unmarshals m into v. diff --git a/core/mapping/unmarshaler_test.go b/core/mapping/unmarshaler_test.go index c45b0600..8916e183 100644 --- a/core/mapping/unmarshaler_test.go +++ b/core/mapping/unmarshaler_test.go @@ -23,7 +23,14 @@ func TestUnmarshalWithFullNameNotStruct(t *testing.T) { var s map[string]interface{} content := []byte(`{"name":"xiaoming"}`) err := UnmarshalJsonBytes(content, &s) - assert.Equal(t, errValueNotStruct, err) + assert.Equal(t, errTypeMismatch, err) +} + +func TestUnmarshalValueNotSettable(t *testing.T) { + var s map[string]interface{} + content := []byte(`{"name":"xiaoming"}`) + err := UnmarshalJsonBytes(content, s) + assert.Equal(t, errValueNotSettable, err) } func TestUnmarshalWithoutTagName(t *testing.T) { diff --git a/rest/httpx/requests_test.go b/rest/httpx/requests_test.go index 70c35c1d..d6601f33 100644 --- a/rest/httpx/requests_test.go +++ b/rest/httpx/requests_test.go @@ -223,6 +223,22 @@ func TestParseJsonBody(t *testing.T) { assert.Equal(t, "", v.Name) assert.Equal(t, 0, v.Age) }) + + t.Run("array body", func(t *testing.T) { + var v []struct { + Name string `json:"name"` + Age int `json:"age"` + } + + body := `[{"name":"kevin", "age": 18}]` + r := httptest.NewRequest(http.MethodPost, "/", strings.NewReader(body)) + r.Header.Set(ContentType, header.JsonContentType) + + assert.NoError(t, ParseJsonBody(r, &v)) + assert.Equal(t, 1, len(v)) + assert.Equal(t, "kevin", v[0].Name) + assert.Equal(t, 18, v[0].Age) + }) } func TestParseRequired(t *testing.T) {