1
0
mirror of https://github.com/json-iterator/go.git synced 2025-05-13 21:36:29 +02:00

Allow null booleans

Make sure we do the same thing as stdlib with null booleans by not
touching the original value and discarding the null.

Another somewhat related change is nulling out null interface values in
the original structure. This also matches stdlib behavior.
This commit is contained in:
Oleg Shaldybin 2017-09-14 16:20:27 -07:00
parent 0fdf883ac0
commit 18a241d40b
3 changed files with 75 additions and 2 deletions

View File

@ -331,7 +331,9 @@ type boolCodec struct {
} }
func (codec *boolCodec) Decode(ptr unsafe.Pointer, iter *Iterator) { func (codec *boolCodec) Decode(ptr unsafe.Pointer, iter *Iterator) {
*((*bool)(ptr)) = iter.ReadBool() if !iter.ReadNil() {
*((*bool)(ptr)) = iter.ReadBool()
}
} }
func (codec *boolCodec) Encode(ptr unsafe.Pointer, stream *Stream) { func (codec *boolCodec) Encode(ptr unsafe.Pointer, stream *Stream) {
@ -350,6 +352,10 @@ type emptyInterfaceCodec struct {
} }
func (codec *emptyInterfaceCodec) Decode(ptr unsafe.Pointer, iter *Iterator) { func (codec *emptyInterfaceCodec) Decode(ptr unsafe.Pointer, iter *Iterator) {
if iter.ReadNil() {
*((*interface{})(ptr)) = nil
return
}
existing := *((*interface{})(ptr)) existing := *((*interface{})(ptr))
if existing != nil && reflect.TypeOf(existing).Kind() == reflect.Ptr { if existing != nil && reflect.TypeOf(existing).Kind() == reflect.Ptr {
iter.ReadVal(existing) iter.ReadVal(existing)

View File

@ -82,3 +82,32 @@ func Test_decode_string_bool(t *testing.T) {
err = Unmarshal([]byte(`{"Field":true}`), &obj) err = Unmarshal([]byte(`{"Field":true}`), &obj)
should.NotNil(err) should.NotNil(err)
} }
func Test_bool_can_be_null(t *testing.T) {
type TestData struct {
Field bool `json:"field"`
}
should := require.New(t)
obj := TestData{}
data1 := []byte(`{"field": true}`)
err := Unmarshal(data1, &obj)
should.Equal(nil, err)
should.Equal(true, obj.Field)
data2 := []byte(`{"field": null}`)
err = Unmarshal(data2, &obj)
should.Equal(nil, err)
// Same behavior as stdlib, not touching the existing value.
should.Equal(true, obj.Field)
// Checking stdlib behavior as well
obj2 := TestData{}
err = json.Unmarshal(data1, &obj2)
should.Equal(nil, err)
should.Equal(true, obj2.Field)
err = json.Unmarshal(data2, &obj2)
should.Equal(nil, err)
should.Equal(true, obj2.Field)
}

View File

@ -3,9 +3,10 @@ package jsoniter
import ( import (
"encoding/json" "encoding/json"
"fmt" "fmt"
"github.com/stretchr/testify/require"
"testing" "testing"
"unsafe" "unsafe"
"github.com/stretchr/testify/require"
) )
func Test_write_array_of_interface(t *testing.T) { func Test_write_array_of_interface(t *testing.T) {
@ -313,3 +314,40 @@ func Test_unmarshal_ptr_to_interface(t *testing.T) {
should.Nil(err) should.Nil(err)
should.Equal("&{value}", fmt.Sprintf("%v", obj)) should.Equal("&{value}", fmt.Sprintf("%v", obj))
} }
func Test_nil_out_null_interface(t *testing.T) {
type TestData struct {
Field interface{} `json:"field"`
}
should := require.New(t)
var boolVar bool
obj := TestData{
Field: &boolVar,
}
data1 := []byte(`{"field": true}`)
err := Unmarshal(data1, &obj)
should.Equal(nil, err)
should.Equal(true, *(obj.Field.(*bool)))
data2 := []byte(`{"field": null}`)
err = Unmarshal(data2, &obj)
should.Equal(nil, err)
should.Equal(nil, obj.Field)
// Checking stdlib behavior matches.
obj2 := TestData{
Field: &boolVar,
}
err = json.Unmarshal(data1, &obj2)
should.Equal(nil, err)
should.Equal(true, *(obj2.Field.(*bool)))
err = json.Unmarshal(data2, &obj2)
should.Equal(nil, err)
should.Equal(nil, obj2.Field)
}