You've already forked json-iterator
							
							
				mirror of
				https://github.com/json-iterator/go.git
				synced 2025-10-31 00:07:40 +02:00 
			
		
		
		
	#23 hide unexported fields by default
This commit is contained in:
		| @@ -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{}{}, | ||||
|   | ||||
| @@ -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) | ||||
| } | ||||
| @@ -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) { | ||||
|   | ||||
		Reference in New Issue
	
	Block a user