mirror of
https://github.com/json-iterator/go.git
synced 2025-06-06 22:36:25 +02:00
#23 hide unexported fields by default
This commit is contained in:
parent
5fbe4e387d
commit
6126a6d3ca
@ -6,32 +6,23 @@ import (
|
|||||||
"reflect"
|
"reflect"
|
||||||
"unsafe"
|
"unsafe"
|
||||||
"strings"
|
"strings"
|
||||||
|
"unicode"
|
||||||
)
|
)
|
||||||
|
|
||||||
func encoderOfStruct(typ reflect.Type) (Encoder, error) {
|
func encoderOfStruct(typ reflect.Type) (Encoder, error) {
|
||||||
structEncoder_ := &structEncoder{}
|
structEncoder_ := &structEncoder{}
|
||||||
for i := 0; i < typ.NumField(); i++ {
|
for i := 0; i < typ.NumField(); i++ {
|
||||||
field := typ.Field(i)
|
field := typ.Field(i)
|
||||||
var fieldNames []string
|
var extensionProvidedFieldNames []string
|
||||||
for _, extension := range extensions {
|
for _, extension := range extensions {
|
||||||
alternativeFieldNames, _ := extension(typ, &field)
|
alternativeFieldNames, _ := extension(typ, &field)
|
||||||
if alternativeFieldNames != nil {
|
if alternativeFieldNames != nil {
|
||||||
fieldNames = alternativeFieldNames
|
extensionProvidedFieldNames = alternativeFieldNames
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
tagParts := strings.Split(field.Tag.Get("json"), ",")
|
tagParts := strings.Split(field.Tag.Get("json"), ",")
|
||||||
// if fieldNames set by extension, use theirs, otherwise try tags
|
// if fieldNames set by extension, use theirs, otherwise try tags
|
||||||
if fieldNames == nil {
|
fieldNames := calcFieldNames(field.Name, tagParts[0], extensionProvidedFieldNames)
|
||||||
/// tagParts[0] always present, even if no tags
|
|
||||||
switch tagParts[0] {
|
|
||||||
case "":
|
|
||||||
fieldNames = []string{field.Name}
|
|
||||||
case "-":
|
|
||||||
fieldNames = []string{}
|
|
||||||
default:
|
|
||||||
fieldNames = []string{tagParts[0]}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
omitempty := false
|
omitempty := false
|
||||||
for _, tagPart := range tagParts {
|
for _, tagPart := range tagParts {
|
||||||
if tagPart == "omitempty" {
|
if tagPart == "omitempty" {
|
||||||
@ -66,11 +57,11 @@ func decoderOfStruct(typ reflect.Type) (Decoder, error) {
|
|||||||
for i := 0; i < typ.NumField(); i++ {
|
for i := 0; i < typ.NumField(); i++ {
|
||||||
field := typ.Field(i)
|
field := typ.Field(i)
|
||||||
fieldDecoderKey := fmt.Sprintf("%s/%s", typ.String(), field.Name)
|
fieldDecoderKey := fmt.Sprintf("%s/%s", typ.String(), field.Name)
|
||||||
var fieldNames []string
|
var extensionProviedFieldNames []string
|
||||||
for _, extension := range extensions {
|
for _, extension := range extensions {
|
||||||
alternativeFieldNames, fun := extension(typ, &field)
|
alternativeFieldNames, fun := extension(typ, &field)
|
||||||
if alternativeFieldNames != nil {
|
if alternativeFieldNames != nil {
|
||||||
fieldNames = alternativeFieldNames
|
extensionProviedFieldNames = alternativeFieldNames
|
||||||
}
|
}
|
||||||
if fun != nil {
|
if fun != nil {
|
||||||
fieldDecoders[fieldDecoderKey] = &funcDecoder{fun}
|
fieldDecoders[fieldDecoderKey] = &funcDecoder{fun}
|
||||||
@ -78,18 +69,7 @@ func decoderOfStruct(typ reflect.Type) (Decoder, error) {
|
|||||||
}
|
}
|
||||||
decoder := fieldDecoders[fieldDecoderKey]
|
decoder := fieldDecoders[fieldDecoderKey]
|
||||||
tagParts := strings.Split(field.Tag.Get("json"), ",")
|
tagParts := strings.Split(field.Tag.Get("json"), ",")
|
||||||
// if fieldNames set by extension, use theirs, otherwise try tags
|
fieldNames := calcFieldNames(field.Name, tagParts[0], extensionProviedFieldNames)
|
||||||
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]}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if decoder == nil && len(fieldNames) > 0 {
|
if decoder == nil && len(fieldNames) > 0 {
|
||||||
var err error
|
var err error
|
||||||
decoder, err = decoderOfType(field.Type)
|
decoder, err = decoderOfType(field.Type)
|
||||||
@ -107,6 +87,36 @@ func decoderOfStruct(typ reflect.Type) (Decoder, error) {
|
|||||||
return createStructDecoder(typ, fields)
|
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) {
|
func createStructDecoder(typ reflect.Type, fields map[string]*structFieldDecoder) (Decoder, error) {
|
||||||
knownHash := map[int32]struct{}{
|
knownHash := map[int32]struct{}{
|
||||||
0: struct{}{},
|
0: struct{}{},
|
||||||
|
@ -103,3 +103,22 @@ func Test_customize_field_by_extension(t *testing.T) {
|
|||||||
t.Fatal(obj.field1)
|
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) {
|
func Test_decode_one_field_struct(t *testing.T) {
|
||||||
should := require.New(t)
|
should := require.New(t)
|
||||||
type TestObject struct {
|
type TestObject struct {
|
||||||
field1 string
|
Field1 string
|
||||||
}
|
}
|
||||||
obj := TestObject{}
|
obj := TestObject{}
|
||||||
should.Nil(UnmarshalFromString(`{}`, &obj))
|
should.Nil(UnmarshalFromString(`{}`, &obj))
|
||||||
should.Equal("", obj.field1)
|
should.Equal("", obj.Field1)
|
||||||
should.Nil(UnmarshalFromString(`{"field1": "hello"}`, &obj))
|
should.Nil(UnmarshalFromString(`{"Field1": "hello"}`, &obj))
|
||||||
should.Equal("hello", obj.field1)
|
should.Equal("hello", obj.Field1)
|
||||||
}
|
}
|
||||||
|
|
||||||
func Test_decode_two_fields_struct(t *testing.T) {
|
func Test_decode_two_fields_struct(t *testing.T) {
|
||||||
should := require.New(t)
|
should := require.New(t)
|
||||||
type TestObject struct {
|
type TestObject struct {
|
||||||
field1 string
|
Field1 string
|
||||||
field2 string
|
Field2 string
|
||||||
}
|
}
|
||||||
obj := TestObject{}
|
obj := TestObject{}
|
||||||
should.Nil(UnmarshalFromString(`{}`, &obj))
|
should.Nil(UnmarshalFromString(`{}`, &obj))
|
||||||
should.Equal("", obj.field1)
|
should.Equal("", obj.Field1)
|
||||||
should.Nil(UnmarshalFromString(`{"field1": "a", "field2": "b"}`, &obj))
|
should.Nil(UnmarshalFromString(`{"Field1": "a", "Field2": "b"}`, &obj))
|
||||||
should.Equal("a", obj.field1)
|
should.Equal("a", obj.Field1)
|
||||||
should.Equal("b", obj.field2)
|
should.Equal("b", obj.Field2)
|
||||||
}
|
}
|
||||||
|
|
||||||
func Test_decode_three_fields_struct(t *testing.T) {
|
func Test_decode_three_fields_struct(t *testing.T) {
|
||||||
should := require.New(t)
|
should := require.New(t)
|
||||||
type TestObject struct {
|
type TestObject struct {
|
||||||
field1 string
|
Field1 string
|
||||||
field2 string
|
Field2 string
|
||||||
field3 string
|
Field3 string
|
||||||
}
|
}
|
||||||
obj := TestObject{}
|
obj := TestObject{}
|
||||||
should.Nil(UnmarshalFromString(`{}`, &obj))
|
should.Nil(UnmarshalFromString(`{}`, &obj))
|
||||||
should.Equal("", obj.field1)
|
should.Equal("", obj.Field1)
|
||||||
should.Nil(UnmarshalFromString(`{"field1": "a", "field2": "b", "field3": "c"}`, &obj))
|
should.Nil(UnmarshalFromString(`{"Field1": "a", "Field2": "b", "Field3": "c"}`, &obj))
|
||||||
should.Equal("a", obj.field1)
|
should.Equal("a", obj.Field1)
|
||||||
should.Equal("b", obj.field2)
|
should.Equal("b", obj.Field2)
|
||||||
should.Equal("c", obj.field3)
|
should.Equal("c", obj.Field3)
|
||||||
}
|
}
|
||||||
|
|
||||||
func Test_decode_four_fields_struct(t *testing.T) {
|
func Test_decode_four_fields_struct(t *testing.T) {
|
||||||
should := require.New(t)
|
should := require.New(t)
|
||||||
type TestObject struct {
|
type TestObject struct {
|
||||||
field1 string
|
Field1 string
|
||||||
field2 string
|
Field2 string
|
||||||
field3 string
|
Field3 string
|
||||||
field4 string
|
Field4 string
|
||||||
}
|
}
|
||||||
obj := TestObject{}
|
obj := TestObject{}
|
||||||
should.Nil(UnmarshalFromString(`{}`, &obj))
|
should.Nil(UnmarshalFromString(`{}`, &obj))
|
||||||
should.Equal("", obj.field1)
|
should.Equal("", obj.Field1)
|
||||||
should.Nil(UnmarshalFromString(`{"field1": "a", "field2": "b", "field3": "c", "field4": "d"}`, &obj))
|
should.Nil(UnmarshalFromString(`{"Field1": "a", "Field2": "b", "Field3": "c", "Field4": "d"}`, &obj))
|
||||||
should.Equal("a", obj.field1)
|
should.Equal("a", obj.Field1)
|
||||||
should.Equal("b", obj.field2)
|
should.Equal("b", obj.Field2)
|
||||||
should.Equal("c", obj.field3)
|
should.Equal("c", obj.Field3)
|
||||||
should.Equal("d", obj.field4)
|
should.Equal("d", obj.Field4)
|
||||||
}
|
}
|
||||||
|
|
||||||
func Test_decode_five_fields_struct(t *testing.T) {
|
func Test_decode_five_fields_struct(t *testing.T) {
|
||||||
should := require.New(t)
|
should := require.New(t)
|
||||||
type TestObject struct {
|
type TestObject struct {
|
||||||
field1 string
|
Field1 string
|
||||||
field2 string
|
Field2 string
|
||||||
field3 string
|
Field3 string
|
||||||
field4 string
|
Field4 string
|
||||||
field5 string
|
Field5 string
|
||||||
}
|
}
|
||||||
obj := TestObject{}
|
obj := TestObject{}
|
||||||
should.Nil(UnmarshalFromString(`{}`, &obj))
|
should.Nil(UnmarshalFromString(`{}`, &obj))
|
||||||
should.Equal("", obj.field1)
|
should.Equal("", obj.Field1)
|
||||||
should.Nil(UnmarshalFromString(`{"field1": "a", "field2": "b", "field3": "c", "field4": "d", "field5": "e"}`, &obj))
|
should.Nil(UnmarshalFromString(`{"Field1": "a", "Field2": "b", "Field3": "c", "Field4": "d", "Field5": "e"}`, &obj))
|
||||||
should.Equal("a", obj.field1)
|
should.Equal("a", obj.Field1)
|
||||||
should.Equal("b", obj.field2)
|
should.Equal("b", obj.Field2)
|
||||||
should.Equal("c", obj.field3)
|
should.Equal("c", obj.Field3)
|
||||||
should.Equal("d", obj.field4)
|
should.Equal("d", obj.Field4)
|
||||||
should.Equal("e", obj.field5)
|
should.Equal("e", obj.Field5)
|
||||||
}
|
}
|
||||||
|
|
||||||
func Test_decode_ten_fields_struct(t *testing.T) {
|
func Test_decode_ten_fields_struct(t *testing.T) {
|
||||||
should := require.New(t)
|
should := require.New(t)
|
||||||
type TestObject struct {
|
type TestObject struct {
|
||||||
field1 string
|
Field1 string
|
||||||
field2 string
|
Field2 string
|
||||||
field3 string
|
Field3 string
|
||||||
field4 string
|
Field4 string
|
||||||
field5 string
|
Field5 string
|
||||||
field6 string
|
Field6 string
|
||||||
field7 string
|
Field7 string
|
||||||
field8 string
|
Field8 string
|
||||||
field9 string
|
Field9 string
|
||||||
field10 string
|
Field10 string
|
||||||
}
|
}
|
||||||
obj := TestObject{}
|
obj := TestObject{}
|
||||||
should.Nil(UnmarshalFromString(`{}`, &obj))
|
should.Nil(UnmarshalFromString(`{}`, &obj))
|
||||||
should.Equal("", obj.field1)
|
should.Equal("", obj.Field1)
|
||||||
should.Nil(UnmarshalFromString(`{"field1": "a", "field2": "b", "field3": "c", "field4": "d", "field5": "e"}`, &obj))
|
should.Nil(UnmarshalFromString(`{"Field1": "a", "Field2": "b", "Field3": "c", "Field4": "d", "Field5": "e"}`, &obj))
|
||||||
should.Equal("a", obj.field1)
|
should.Equal("a", obj.Field1)
|
||||||
should.Equal("b", obj.field2)
|
should.Equal("b", obj.Field2)
|
||||||
should.Equal("c", obj.field3)
|
should.Equal("c", obj.Field3)
|
||||||
should.Equal("d", obj.field4)
|
should.Equal("d", obj.Field4)
|
||||||
should.Equal("e", obj.field5)
|
should.Equal("e", obj.Field5)
|
||||||
}
|
}
|
||||||
|
|
||||||
func Test_decode_struct_field_with_tag(t *testing.T) {
|
func Test_decode_struct_field_with_tag(t *testing.T) {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user