Explorar o código

#23 hide unexported fields by default

Tao Wen %!s(int64=8) %!d(string=hai) anos
pai
achega
6126a6d3ca
Modificáronse 3 ficheiros con 113 adicións e 84 borrados
  1. 37 27
      feature_reflect_object.go
  2. 19 0
      jsoniter_customize_test.go
  3. 57 57
      jsoniter_reflect_struct_test.go

+ 37 - 27
feature_reflect_object.go

@@ -6,32 +6,23 @@ import (
 	"reflect"
 	"unsafe"
 	"strings"
+	"unicode"
 )
 
 func encoderOfStruct(typ reflect.Type) (Encoder, error) {
 	structEncoder_ := &structEncoder{}
 	for i := 0; i < typ.NumField(); i++ {
 		field := typ.Field(i)
-		var fieldNames []string
+		var extensionProvidedFieldNames []string
 		for _, extension := range extensions {
 			alternativeFieldNames, _ := extension(typ, &field)
 			if alternativeFieldNames != nil {
-				fieldNames = alternativeFieldNames
+				extensionProvidedFieldNames = alternativeFieldNames
 			}
 		}
 		tagParts := strings.Split(field.Tag.Get("json"), ",")
 		// if fieldNames set by extension, use theirs, otherwise try tags
-		if fieldNames == nil {
-			/// tagParts[0] always present, even if no tags
-			switch tagParts[0] {
-			case "":
-				fieldNames = []string{field.Name}
-			case "-":
-				fieldNames = []string{}
-			default:
-				fieldNames = []string{tagParts[0]}
-			}
-		}
+		fieldNames := calcFieldNames(field.Name, tagParts[0], extensionProvidedFieldNames)
 		omitempty := false
 		for _, tagPart := range tagParts {
 			if tagPart == "omitempty" {
@@ -66,11 +57,11 @@ func decoderOfStruct(typ reflect.Type) (Decoder, error) {
 	for i := 0; i < typ.NumField(); i++ {
 		field := typ.Field(i)
 		fieldDecoderKey := fmt.Sprintf("%s/%s", typ.String(), field.Name)
-		var fieldNames []string
+		var extensionProviedFieldNames []string
 		for _, extension := range extensions {
 			alternativeFieldNames, fun := extension(typ, &field)
 			if alternativeFieldNames != nil {
-				fieldNames = alternativeFieldNames
+				extensionProviedFieldNames = alternativeFieldNames
 			}
 			if fun != nil {
 				fieldDecoders[fieldDecoderKey] = &funcDecoder{fun}
@@ -78,18 +69,7 @@ func decoderOfStruct(typ reflect.Type) (Decoder, error) {
 		}
 		decoder := fieldDecoders[fieldDecoderKey]
 		tagParts := strings.Split(field.Tag.Get("json"), ",")
-		// if fieldNames set by extension, use theirs, otherwise try tags
-		if fieldNames == nil {
-			/// tagParts[0] always present, even if no tags
-			switch tagParts[0] {
-			case "":
-				fieldNames = []string{field.Name}
-			case "-":
-				fieldNames = []string{}
-			default:
-				fieldNames = []string{tagParts[0]}
-			}
-		}
+		fieldNames := calcFieldNames(field.Name, tagParts[0], extensionProviedFieldNames)
 		if decoder == nil && len(fieldNames) > 0 {
 			var err error
 			decoder, err = decoderOfType(field.Type)
@@ -107,6 +87,36 @@ func decoderOfStruct(typ reflect.Type) (Decoder, error) {
 	return createStructDecoder(typ, fields)
 }
 
+func calcFieldNames(originalFieldName string, tagProvidedFieldName string, extensionProvidedFieldNames []string) []string {
+	// tag => extension => exported? => original
+	isNotExported := unicode.IsLower(rune(originalFieldName[0]))
+	var fieldNames []string
+	/// tagParts[0] always present, even if no tags
+	switch tagProvidedFieldName {
+	case "":
+		if extensionProvidedFieldNames != nil {
+			fieldNames = extensionProvidedFieldNames
+		} else {
+			if isNotExported {
+				fieldNames = []string{}
+			} else {
+				fieldNames = []string{originalFieldName}
+			}
+		}
+	case "-":
+		fieldNames = []string{}
+	default:
+		fieldNames = []string{tagProvidedFieldName}
+	}
+	return fieldNames
+}
+
+func EnableUnexportedStructFieldsSupport() {
+	RegisterExtension(func(type_ reflect.Type, field *reflect.StructField) ([]string, DecoderFunc) {
+		return []string{field.Name}, nil
+	})
+}
+
 func createStructDecoder(typ reflect.Type, fields map[string]*structFieldDecoder) (Decoder, error) {
 	knownHash := map[int32]struct{}{
 		0: struct{}{},

+ 19 - 0
jsoniter_customize_test.go

@@ -103,3 +103,22 @@ func Test_customize_field_by_extension(t *testing.T) {
 		t.Fatal(obj.field1)
 	}
 }
+
+func Test_unexported_fields(t *testing.T) {
+	EnableUnexportedStructFieldsSupport()
+	should := require.New(t)
+	type TestObject struct {
+		field1 string
+		field2 string `json:"field-2"`
+	}
+	obj := TestObject{}
+	obj.field1 = "hello"
+	should.Nil(UnmarshalFromString(`{}`, &obj))
+	should.Equal("hello", obj.field1)
+	should.Nil(UnmarshalFromString(`{"field1": "world", "field-2": "abc"}`, &obj))
+	should.Equal("world", obj.field1)
+	should.Equal("abc", obj.field2)
+	str, err := MarshalToString(obj)
+	should.Nil(err)
+	should.Equal(`{"field1":"world","field-2":"abc"}`, str)
+}

+ 57 - 57
jsoniter_reflect_struct_test.go

@@ -9,106 +9,106 @@ import (
 func Test_decode_one_field_struct(t *testing.T) {
 	should := require.New(t)
 	type TestObject struct {
-		field1 string
+		Field1 string
 	}
 	obj := TestObject{}
 	should.Nil(UnmarshalFromString(`{}`, &obj))
-	should.Equal("", obj.field1)
-	should.Nil(UnmarshalFromString(`{"field1": "hello"}`, &obj))
-	should.Equal("hello", obj.field1)
+	should.Equal("", obj.Field1)
+	should.Nil(UnmarshalFromString(`{"Field1": "hello"}`, &obj))
+	should.Equal("hello", obj.Field1)
 }
 
 func Test_decode_two_fields_struct(t *testing.T) {
 	should := require.New(t)
 	type TestObject struct {
-		field1 string
-		field2 string
+		Field1 string
+		Field2 string
 	}
 	obj := TestObject{}
 	should.Nil(UnmarshalFromString(`{}`, &obj))
-	should.Equal("", obj.field1)
-	should.Nil(UnmarshalFromString(`{"field1": "a", "field2": "b"}`, &obj))
-	should.Equal("a", obj.field1)
-	should.Equal("b", obj.field2)
+	should.Equal("", obj.Field1)
+	should.Nil(UnmarshalFromString(`{"Field1": "a", "Field2": "b"}`, &obj))
+	should.Equal("a", obj.Field1)
+	should.Equal("b", obj.Field2)
 }
 
 func Test_decode_three_fields_struct(t *testing.T) {
 	should := require.New(t)
 	type TestObject struct {
-		field1 string
-		field2 string
-		field3 string
+		Field1 string
+		Field2 string
+		Field3 string
 	}
 	obj := TestObject{}
 	should.Nil(UnmarshalFromString(`{}`, &obj))
-	should.Equal("", obj.field1)
-	should.Nil(UnmarshalFromString(`{"field1": "a", "field2": "b", "field3": "c"}`, &obj))
-	should.Equal("a", obj.field1)
-	should.Equal("b", obj.field2)
-	should.Equal("c", obj.field3)
+	should.Equal("", obj.Field1)
+	should.Nil(UnmarshalFromString(`{"Field1": "a", "Field2": "b", "Field3": "c"}`, &obj))
+	should.Equal("a", obj.Field1)
+	should.Equal("b", obj.Field2)
+	should.Equal("c", obj.Field3)
 }
 
 func Test_decode_four_fields_struct(t *testing.T) {
 	should := require.New(t)
 	type TestObject struct {
-		field1 string
-		field2 string
-		field3 string
-		field4 string
+		Field1 string
+		Field2 string
+		Field3 string
+		Field4 string
 	}
 	obj := TestObject{}
 	should.Nil(UnmarshalFromString(`{}`, &obj))
-	should.Equal("", obj.field1)
-	should.Nil(UnmarshalFromString(`{"field1": "a", "field2": "b", "field3": "c", "field4": "d"}`, &obj))
-	should.Equal("a", obj.field1)
-	should.Equal("b", obj.field2)
-	should.Equal("c", obj.field3)
-	should.Equal("d", obj.field4)
+	should.Equal("", obj.Field1)
+	should.Nil(UnmarshalFromString(`{"Field1": "a", "Field2": "b", "Field3": "c", "Field4": "d"}`, &obj))
+	should.Equal("a", obj.Field1)
+	should.Equal("b", obj.Field2)
+	should.Equal("c", obj.Field3)
+	should.Equal("d", obj.Field4)
 }
 
 func Test_decode_five_fields_struct(t *testing.T) {
 	should := require.New(t)
 	type TestObject struct {
-		field1 string
-		field2 string
-		field3 string
-		field4 string
-		field5 string
+		Field1 string
+		Field2 string
+		Field3 string
+		Field4 string
+		Field5 string
 	}
 	obj := TestObject{}
 	should.Nil(UnmarshalFromString(`{}`, &obj))
-	should.Equal("", obj.field1)
-	should.Nil(UnmarshalFromString(`{"field1": "a", "field2": "b", "field3": "c", "field4": "d", "field5": "e"}`, &obj))
-	should.Equal("a", obj.field1)
-	should.Equal("b", obj.field2)
-	should.Equal("c", obj.field3)
-	should.Equal("d", obj.field4)
-	should.Equal("e", obj.field5)
+	should.Equal("", obj.Field1)
+	should.Nil(UnmarshalFromString(`{"Field1": "a", "Field2": "b", "Field3": "c", "Field4": "d", "Field5": "e"}`, &obj))
+	should.Equal("a", obj.Field1)
+	should.Equal("b", obj.Field2)
+	should.Equal("c", obj.Field3)
+	should.Equal("d", obj.Field4)
+	should.Equal("e", obj.Field5)
 }
 
 func Test_decode_ten_fields_struct(t *testing.T) {
 	should := require.New(t)
 	type TestObject struct {
-		field1  string
-		field2  string
-		field3  string
-		field4  string
-		field5  string
-		field6  string
-		field7  string
-		field8  string
-		field9  string
-		field10 string
+		Field1  string
+		Field2  string
+		Field3  string
+		Field4  string
+		Field5  string
+		Field6  string
+		Field7  string
+		Field8  string
+		Field9  string
+		Field10 string
 	}
 	obj := TestObject{}
 	should.Nil(UnmarshalFromString(`{}`, &obj))
-	should.Equal("", obj.field1)
-	should.Nil(UnmarshalFromString(`{"field1": "a", "field2": "b", "field3": "c", "field4": "d", "field5": "e"}`, &obj))
-	should.Equal("a", obj.field1)
-	should.Equal("b", obj.field2)
-	should.Equal("c", obj.field3)
-	should.Equal("d", obj.field4)
-	should.Equal("e", obj.field5)
+	should.Equal("", obj.Field1)
+	should.Nil(UnmarshalFromString(`{"Field1": "a", "Field2": "b", "Field3": "c", "Field4": "d", "Field5": "e"}`, &obj))
+	should.Equal("a", obj.Field1)
+	should.Equal("b", obj.Field2)
+	should.Equal("c", obj.Field3)
+	should.Equal("d", obj.Field4)
+	should.Equal("e", obj.Field5)
 }
 
 func Test_decode_struct_field_with_tag(t *testing.T) {