Skip to content

Commit f8eb43e

Browse files
authored
Merge pull request #168 from olegshaldybin/null-booleans
Allow null booleans
2 parents 0fdf883 + 18a241d commit f8eb43e

File tree

3 files changed

+75
-2
lines changed

3 files changed

+75
-2
lines changed

feature_reflect_native.go

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -331,7 +331,9 @@ type boolCodec struct {
331331
}
332332

333333
func (codec *boolCodec) Decode(ptr unsafe.Pointer, iter *Iterator) {
334-
*((*bool)(ptr)) = iter.ReadBool()
334+
if !iter.ReadNil() {
335+
*((*bool)(ptr)) = iter.ReadBool()
336+
}
335337
}
336338

337339
func (codec *boolCodec) Encode(ptr unsafe.Pointer, stream *Stream) {
@@ -350,6 +352,10 @@ type emptyInterfaceCodec struct {
350352
}
351353

352354
func (codec *emptyInterfaceCodec) Decode(ptr unsafe.Pointer, iter *Iterator) {
355+
if iter.ReadNil() {
356+
*((*interface{})(ptr)) = nil
357+
return
358+
}
353359
existing := *((*interface{})(ptr))
354360
if existing != nil && reflect.TypeOf(existing).Kind() == reflect.Ptr {
355361
iter.ReadVal(existing)

jsoniter_bool_test.go

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -82,3 +82,32 @@ func Test_decode_string_bool(t *testing.T) {
8282
err = Unmarshal([]byte(`{"Field":true}`), &obj)
8383
should.NotNil(err)
8484
}
85+
86+
func Test_bool_can_be_null(t *testing.T) {
87+
type TestData struct {
88+
Field bool `json:"field"`
89+
}
90+
should := require.New(t)
91+
92+
obj := TestData{}
93+
data1 := []byte(`{"field": true}`)
94+
err := Unmarshal(data1, &obj)
95+
should.Equal(nil, err)
96+
should.Equal(true, obj.Field)
97+
98+
data2 := []byte(`{"field": null}`)
99+
err = Unmarshal(data2, &obj)
100+
should.Equal(nil, err)
101+
// Same behavior as stdlib, not touching the existing value.
102+
should.Equal(true, obj.Field)
103+
104+
// Checking stdlib behavior as well
105+
obj2 := TestData{}
106+
err = json.Unmarshal(data1, &obj2)
107+
should.Equal(nil, err)
108+
should.Equal(true, obj2.Field)
109+
110+
err = json.Unmarshal(data2, &obj2)
111+
should.Equal(nil, err)
112+
should.Equal(true, obj2.Field)
113+
}

jsoniter_interface_test.go

Lines changed: 39 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,10 @@ package jsoniter
33
import (
44
"encoding/json"
55
"fmt"
6-
"github.com/stretchr/testify/require"
76
"testing"
87
"unsafe"
8+
9+
"github.com/stretchr/testify/require"
910
)
1011

1112
func Test_write_array_of_interface(t *testing.T) {
@@ -313,3 +314,40 @@ func Test_unmarshal_ptr_to_interface(t *testing.T) {
313314
should.Nil(err)
314315
should.Equal("&{value}", fmt.Sprintf("%v", obj))
315316
}
317+
318+
func Test_nil_out_null_interface(t *testing.T) {
319+
type TestData struct {
320+
Field interface{} `json:"field"`
321+
}
322+
should := require.New(t)
323+
324+
var boolVar bool
325+
obj := TestData{
326+
Field: &boolVar,
327+
}
328+
329+
data1 := []byte(`{"field": true}`)
330+
331+
err := Unmarshal(data1, &obj)
332+
should.Equal(nil, err)
333+
should.Equal(true, *(obj.Field.(*bool)))
334+
335+
data2 := []byte(`{"field": null}`)
336+
337+
err = Unmarshal(data2, &obj)
338+
should.Equal(nil, err)
339+
should.Equal(nil, obj.Field)
340+
341+
// Checking stdlib behavior matches.
342+
obj2 := TestData{
343+
Field: &boolVar,
344+
}
345+
346+
err = json.Unmarshal(data1, &obj2)
347+
should.Equal(nil, err)
348+
should.Equal(true, *(obj2.Field.(*bool)))
349+
350+
err = json.Unmarshal(data2, &obj2)
351+
should.Equal(nil, err)
352+
should.Equal(nil, obj2.Field)
353+
}

0 commit comments

Comments
 (0)