You've already forked json-iterator
mirror of
https://github.com/json-iterator/go.git
synced 2025-06-24 23:16:47 +02:00
Merge pull request #173 from toffaletti/more-nil-interface-fixes
More nil interface fixes
This commit is contained in:
@ -391,15 +391,20 @@ func (codec *nonEmptyInterfaceCodec) Decode(ptr unsafe.Pointer, iter *Iterator)
|
|||||||
e.typ = nonEmptyInterface.itab.typ
|
e.typ = nonEmptyInterface.itab.typ
|
||||||
e.word = nonEmptyInterface.word
|
e.word = nonEmptyInterface.word
|
||||||
iter.ReadVal(&i)
|
iter.ReadVal(&i)
|
||||||
|
if e.word == nil {
|
||||||
|
nonEmptyInterface.itab = nil
|
||||||
|
}
|
||||||
nonEmptyInterface.word = e.word
|
nonEmptyInterface.word = e.word
|
||||||
}
|
}
|
||||||
|
|
||||||
func (codec *nonEmptyInterfaceCodec) Encode(ptr unsafe.Pointer, stream *Stream) {
|
func (codec *nonEmptyInterfaceCodec) Encode(ptr unsafe.Pointer, stream *Stream) {
|
||||||
nonEmptyInterface := (*nonEmptyInterface)(ptr)
|
nonEmptyInterface := (*nonEmptyInterface)(ptr)
|
||||||
var i interface{}
|
var i interface{}
|
||||||
|
if nonEmptyInterface.itab != nil {
|
||||||
e := (*emptyInterface)(unsafe.Pointer(&i))
|
e := (*emptyInterface)(unsafe.Pointer(&i))
|
||||||
e.typ = nonEmptyInterface.itab.typ
|
e.typ = nonEmptyInterface.itab.typ
|
||||||
e.word = nonEmptyInterface.word
|
e.word = nonEmptyInterface.word
|
||||||
|
}
|
||||||
stream.WriteVal(i)
|
stream.WriteVal(i)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -660,7 +665,11 @@ func (encoder *marshalerEncoder) Encode(ptr unsafe.Pointer, stream *Stream) {
|
|||||||
templateInterface := encoder.templateInterface
|
templateInterface := encoder.templateInterface
|
||||||
templateInterface.word = ptr
|
templateInterface.word = ptr
|
||||||
realInterface := (*interface{})(unsafe.Pointer(&templateInterface))
|
realInterface := (*interface{})(unsafe.Pointer(&templateInterface))
|
||||||
marshaler := (*realInterface).(json.Marshaler)
|
marshaler, ok := (*realInterface).(json.Marshaler)
|
||||||
|
if !ok {
|
||||||
|
stream.WriteVal(nil)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
bytes, err := marshaler.MarshalJSON()
|
bytes, err := marshaler.MarshalJSON()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -92,22 +92,22 @@ func Test_bool_can_be_null(t *testing.T) {
|
|||||||
obj := TestData{}
|
obj := TestData{}
|
||||||
data1 := []byte(`{"field": true}`)
|
data1 := []byte(`{"field": true}`)
|
||||||
err := Unmarshal(data1, &obj)
|
err := Unmarshal(data1, &obj)
|
||||||
should.Equal(nil, err)
|
should.NoError(err)
|
||||||
should.Equal(true, obj.Field)
|
should.Equal(true, obj.Field)
|
||||||
|
|
||||||
data2 := []byte(`{"field": null}`)
|
data2 := []byte(`{"field": null}`)
|
||||||
err = Unmarshal(data2, &obj)
|
err = Unmarshal(data2, &obj)
|
||||||
should.Equal(nil, err)
|
should.NoError(err)
|
||||||
// Same behavior as stdlib, not touching the existing value.
|
// Same behavior as stdlib, not touching the existing value.
|
||||||
should.Equal(true, obj.Field)
|
should.Equal(true, obj.Field)
|
||||||
|
|
||||||
// Checking stdlib behavior as well
|
// Checking stdlib behavior as well
|
||||||
obj2 := TestData{}
|
obj2 := TestData{}
|
||||||
err = json.Unmarshal(data1, &obj2)
|
err = json.Unmarshal(data1, &obj2)
|
||||||
should.Equal(nil, err)
|
should.NoError(err)
|
||||||
should.Equal(true, obj2.Field)
|
should.Equal(true, obj2.Field)
|
||||||
|
|
||||||
err = json.Unmarshal(data2, &obj2)
|
err = json.Unmarshal(data2, &obj2)
|
||||||
should.Equal(nil, err)
|
should.NoError(err)
|
||||||
should.Equal(true, obj2.Field)
|
should.Equal(true, obj2.Field)
|
||||||
}
|
}
|
||||||
|
@ -40,11 +40,11 @@ func Test_custom_marshaler_on_enum(t *testing.T) {
|
|||||||
w := Wrapper{Payload: MyEnumB}
|
w := Wrapper{Payload: MyEnumB}
|
||||||
|
|
||||||
jb, err := Marshal(w)
|
jb, err := Marshal(w)
|
||||||
should.Equal(nil, err)
|
should.NoError(err)
|
||||||
should.Equal(`{"Payload":"foo-1"}`, string(jb))
|
should.Equal(`{"Payload":"foo-1"}`, string(jb))
|
||||||
|
|
||||||
var w2 Wrapper2
|
var w2 Wrapper2
|
||||||
err = Unmarshal(jb, &w2)
|
err = Unmarshal(jb, &w2)
|
||||||
should.Equal(nil, err)
|
should.NoError(err)
|
||||||
should.Equal(MyEnumB, w2.Payload)
|
should.Equal(MyEnumB, w2.Payload)
|
||||||
}
|
}
|
||||||
|
@ -329,13 +329,13 @@ func Test_nil_out_null_interface(t *testing.T) {
|
|||||||
data1 := []byte(`{"field": true}`)
|
data1 := []byte(`{"field": true}`)
|
||||||
|
|
||||||
err := Unmarshal(data1, &obj)
|
err := Unmarshal(data1, &obj)
|
||||||
should.Equal(nil, err)
|
should.NoError(err)
|
||||||
should.Equal(true, *(obj.Field.(*bool)))
|
should.Equal(true, *(obj.Field.(*bool)))
|
||||||
|
|
||||||
data2 := []byte(`{"field": null}`)
|
data2 := []byte(`{"field": null}`)
|
||||||
|
|
||||||
err = Unmarshal(data2, &obj)
|
err = Unmarshal(data2, &obj)
|
||||||
should.Equal(nil, err)
|
should.NoError(err)
|
||||||
should.Equal(nil, obj.Field)
|
should.Equal(nil, obj.Field)
|
||||||
|
|
||||||
// Checking stdlib behavior matches.
|
// Checking stdlib behavior matches.
|
||||||
@ -344,11 +344,11 @@ func Test_nil_out_null_interface(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
err = json.Unmarshal(data1, &obj2)
|
err = json.Unmarshal(data1, &obj2)
|
||||||
should.Equal(nil, err)
|
should.NoError(err)
|
||||||
should.Equal(true, *(obj2.Field.(*bool)))
|
should.Equal(true, *(obj2.Field.(*bool)))
|
||||||
|
|
||||||
err = json.Unmarshal(data2, &obj2)
|
err = json.Unmarshal(data2, &obj2)
|
||||||
should.Equal(nil, err)
|
should.NoError(err)
|
||||||
should.Equal(nil, obj2.Field)
|
should.Equal(nil, obj2.Field)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -363,10 +363,77 @@ func Test_omitempty_nil_interface(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
js, err := json.Marshal(obj)
|
js, err := json.Marshal(obj)
|
||||||
should.Equal(nil, err)
|
should.NoError(err)
|
||||||
should.Equal("{}", string(js))
|
should.Equal("{}", string(js))
|
||||||
|
|
||||||
str, err := MarshalToString(obj)
|
str, err := MarshalToString(obj)
|
||||||
should.Equal(nil, err)
|
should.NoError(err)
|
||||||
should.Equal(string(js), str)
|
should.Equal(string(js), str)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func Test_omitempty_nil_nonempty_interface(t *testing.T) {
|
||||||
|
type TestData struct {
|
||||||
|
Field MyInterface `json:"field,omitempty"`
|
||||||
|
}
|
||||||
|
should := require.New(t)
|
||||||
|
|
||||||
|
obj := TestData{
|
||||||
|
Field: nil,
|
||||||
|
}
|
||||||
|
|
||||||
|
js, err := json.Marshal(obj)
|
||||||
|
should.NoError(err)
|
||||||
|
should.Equal("{}", string(js))
|
||||||
|
|
||||||
|
str, err := MarshalToString(obj)
|
||||||
|
should.NoError(err)
|
||||||
|
should.Equal(string(js), str)
|
||||||
|
|
||||||
|
obj.Field = MyString("hello")
|
||||||
|
err = UnmarshalFromString(`{"field":null}`, &obj)
|
||||||
|
should.NoError(err)
|
||||||
|
should.Equal(nil, obj.Field)
|
||||||
|
}
|
||||||
|
|
||||||
|
func Test_marshal_nil_marshaler_interface(t *testing.T) {
|
||||||
|
type TestData struct {
|
||||||
|
Field json.Marshaler `json:"field"`
|
||||||
|
}
|
||||||
|
should := require.New(t)
|
||||||
|
|
||||||
|
obj := TestData{
|
||||||
|
Field: nil,
|
||||||
|
}
|
||||||
|
|
||||||
|
js, err := json.Marshal(obj)
|
||||||
|
should.NoError(err)
|
||||||
|
should.Equal(`{"field":null}`, string(js))
|
||||||
|
|
||||||
|
str, err := MarshalToString(obj)
|
||||||
|
should.NoError(err)
|
||||||
|
should.Equal(string(js), str)
|
||||||
|
}
|
||||||
|
|
||||||
|
func Test_marshal_nil_nonempty_interface(t *testing.T) {
|
||||||
|
type TestData struct {
|
||||||
|
Field MyInterface `json:"field"`
|
||||||
|
}
|
||||||
|
should := require.New(t)
|
||||||
|
|
||||||
|
obj := TestData{
|
||||||
|
Field: nil,
|
||||||
|
}
|
||||||
|
|
||||||
|
js, err := json.Marshal(obj)
|
||||||
|
should.NoError(err)
|
||||||
|
should.Equal(`{"field":null}`, string(js))
|
||||||
|
|
||||||
|
str, err := MarshalToString(obj)
|
||||||
|
should.NoError(err)
|
||||||
|
should.Equal(string(js), str)
|
||||||
|
|
||||||
|
obj.Field = MyString("hello")
|
||||||
|
err = Unmarshal(js, &obj)
|
||||||
|
should.NoError(err)
|
||||||
|
should.Equal(nil, obj.Field)
|
||||||
|
}
|
||||||
|
Reference in New Issue
Block a user