diff --git a/core/mapping/unmarshaler.go b/core/mapping/unmarshaler.go index 303805dd..b86ef8f4 100644 --- a/core/mapping/unmarshaler.go +++ b/core/mapping/unmarshaler.go @@ -271,6 +271,10 @@ func (u *Unmarshaler) processFieldPrimitiveWithJSONNumber(field reflect.StructFi return err } + if iValue < 0 { + return fmt.Errorf("unmarshal %q with bad value %q", fullName, v.String()) + } + value.SetUint(uint64(iValue)) case reflect.Float32, reflect.Float64: fValue, err := v.Float64() @@ -727,10 +731,10 @@ func fillWithSameType(field reflect.StructField, value reflect.Value, mapValue i if field.Type.Kind() == reflect.Ptr { baseType := Deref(field.Type) target := reflect.New(baseType).Elem() - target.Set(reflect.ValueOf(mapValue)) + setSameKindValue(baseType, target, mapValue) value.Set(target.Addr()) } else { - value.Set(reflect.ValueOf(mapValue)) + setSameKindValue(field.Type, value, mapValue) } return nil @@ -805,3 +809,11 @@ func readKeys(key string) []string { return keys } + +func setSameKindValue(targetType reflect.Type, target reflect.Value, value interface{}) { + if reflect.ValueOf(value).Type().AssignableTo(targetType) { + target.Set(reflect.ValueOf(value)) + } else { + target.Set(reflect.ValueOf(value).Convert(targetType)) + } +} diff --git a/core/mapping/unmarshaler_test.go b/core/mapping/unmarshaler_test.go index 1b3bdcfc..2cf21520 100644 --- a/core/mapping/unmarshaler_test.go +++ b/core/mapping/unmarshaler_test.go @@ -2660,6 +2660,86 @@ func TestUnmarshalJsonWithoutKey(t *testing.T) { assert.Equal(t, "2", res.B) } +func TestUnmarshalJsonUintNegative(t *testing.T) { + payload := `{"a": -1}` + var res struct { + A uint `json:"a"` + } + reader := strings.NewReader(payload) + err := UnmarshalJsonReader(reader, &res) + assert.NotNil(t, err) +} + +func TestUnmarshalJsonDefinedInt(t *testing.T) { + type Int int + var res struct { + A Int `json:"a"` + } + payload := `{"a": -1}` + reader := strings.NewReader(payload) + err := UnmarshalJsonReader(reader, &res) + assert.Nil(t, err) + assert.Equal(t, Int(-1), res.A) +} + +func TestUnmarshalJsonDefinedString(t *testing.T) { + type String string + var res struct { + A String `json:"a"` + } + payload := `{"a": "foo"}` + reader := strings.NewReader(payload) + err := UnmarshalJsonReader(reader, &res) + assert.Nil(t, err) + assert.Equal(t, String("foo"), res.A) +} + +func TestUnmarshalJsonDefinedStringPtr(t *testing.T) { + type String string + var res struct { + A *String `json:"a"` + } + payload := `{"a": "foo"}` + reader := strings.NewReader(payload) + err := UnmarshalJsonReader(reader, &res) + assert.Nil(t, err) + assert.Equal(t, String("foo"), *res.A) +} + +func TestUnmarshalJsonReaderComplex(t *testing.T) { + type ( + MyInt int + MyTxt string + MyTxtArray []string + + Req struct { + MyInt MyInt `json:"my_int"` // int.. ok + MyTxtArray MyTxtArray `json:"my_txt_array"` + MyTxt MyTxt `json:"my_txt"` // but string is not assignable + Int int `json:"int"` + Txt string `json:"txt"` + } + ) + body := `{ + "my_int": 100, + "my_txt_array": [ + "a", + "b" + ], + "my_txt": "my_txt", + "int": 200, + "txt": "txt" +}` + var req Req + err := UnmarshalJsonReader(strings.NewReader(body), &req) + assert.Nil(t, err) + assert.Equal(t, MyInt(100), req.MyInt) + assert.Equal(t, MyTxt("my_txt"), req.MyTxt) + assert.EqualValues(t, MyTxtArray([]string{"a", "b"}), req.MyTxtArray) + assert.Equal(t, 200, req.Int) + assert.Equal(t, "txt", req.Txt) +} + func BenchmarkDefaultValue(b *testing.B) { for i := 0; i < b.N; i++ { var a struct {