Sfoglia il codice sorgente

Always skip unexported fields when encoding

Skip creating encoders for unexported fields. They are not participating
in JSON marshaling anyway. This allows using unexported fields of
non-marshalable types in structs.

As a side-effect of this change it's no longer possible to marshal
unexported JSON fields by adding a custom type extenstion. It seems this
is desired behavior since it matches standard library and jsoniter
already disallows `json:"-"` fields from participating in custom
extensions.

Fixes #174.
Oleg Shaldybin 8 anni fa
parent
commit
1f58120d43

+ 3 - 0
feature_reflect_extension.go

@@ -227,6 +227,9 @@ func describeStruct(cfg *frozenConfig, typ reflect.Type) (*StructDescriptor, err
 	bindings := []*Binding{}
 	for i := 0; i < typ.NumField(); i++ {
 		field := typ.Field(i)
+		if unicode.IsLower([]rune(field.Name)[0]) {
+			continue
+		}
 		tag := field.Tag.Get(cfg.getTagKey())
 		tagParts := strings.Split(tag, ",")
 		if tag == "-" {

+ 5 - 4
jsoniter_customize_test.go

@@ -2,11 +2,12 @@ package jsoniter
 
 import (
 	"encoding/json"
-	"github.com/stretchr/testify/require"
 	"strconv"
 	"testing"
 	"time"
 	"unsafe"
+
+	"github.com/stretchr/testify/require"
 )
 
 func Test_customize_type_decoder(t *testing.T) {
@@ -82,7 +83,7 @@ func Test_customize_field_decoder(t *testing.T) {
 }
 
 type TestObject1 struct {
-	field1 string
+	Field1 string
 }
 
 type testExtension struct {
@@ -93,7 +94,7 @@ func (extension *testExtension) UpdateStructDescriptor(structDescriptor *StructD
 	if structDescriptor.Type.String() != "jsoniter.TestObject1" {
 		return
 	}
-	binding := structDescriptor.GetField("field1")
+	binding := structDescriptor.GetField("Field1")
 	binding.Encoder = &funcEncoder{fun: func(ptr unsafe.Pointer, stream *Stream) {
 		str := *((*string)(ptr))
 		val, _ := strconv.Atoi(str)
@@ -112,7 +113,7 @@ func Test_customize_field_by_extension(t *testing.T) {
 	obj := TestObject1{}
 	err := UnmarshalFromString(`{"field-1": 100}`, &obj)
 	should.Nil(err)
-	should.Equal("100", obj.field1)
+	should.Equal("100", obj.Field1)
 	str, err := MarshalToString(obj)
 	should.Nil(err)
 	should.Equal(`{"field-1":100}`, str)

+ 52 - 0
jsoniter_struct_encoder_test.go

@@ -0,0 +1,52 @@
+package jsoniter
+
+import (
+	"encoding/json"
+	"testing"
+	"time"
+
+	"github.com/stretchr/testify/require"
+)
+
+func Test_encode_unexported_field(t *testing.T) {
+	type TestData struct {
+		a int
+		b <-chan int
+		C int
+		d *time.Timer
+	}
+
+	should := require.New(t)
+
+	testChan := make(<-chan int, 10)
+	testTimer := time.NewTimer(10 * time.Second)
+
+	obj := &TestData{
+		a: 42,
+		b: testChan,
+		C: 21,
+		d: testTimer,
+	}
+
+	jb, err := json.Marshal(obj)
+	should.NoError(err)
+	should.Equal([]byte(`{"C":21}`), jb)
+
+	err = json.Unmarshal([]byte(`{"a": 444, "b":"bad", "C":55, "d":{"not": "a timer"}}`), obj)
+	should.NoError(err)
+	should.Equal(42, obj.a)
+	should.Equal(testChan, obj.b)
+	should.Equal(55, obj.C)
+	should.Equal(testTimer, obj.d)
+
+	jb, err = Marshal(obj)
+	should.NoError(err)
+	should.Equal(jb, []byte(`{"C":55}`))
+
+	err = Unmarshal([]byte(`{"a": 444, "b":"bad", "C":256, "d":{"not":"a timer"}}`), obj)
+	should.NoError(err)
+	should.Equal(42, obj.a)
+	should.Equal(testChan, obj.b)
+	should.Equal(256, obj.C)
+	should.Equal(testTimer, obj.d)
+}