mirror of
https://github.com/json-iterator/go.git
synced 2025-04-14 11:18:49 +02:00
#81 handle field name conflict properly
This commit is contained in:
parent
e6c24947ee
commit
09cb1d9236
@ -31,6 +31,7 @@ func (structDescriptor *StructDescriptor) GetField(fieldName string) *Binding {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type Binding struct {
|
type Binding struct {
|
||||||
|
levels []int
|
||||||
Field *reflect.StructField
|
Field *reflect.StructField
|
||||||
FromNames []string
|
FromNames []string
|
||||||
ToNames []string
|
ToNames []string
|
||||||
@ -206,6 +207,7 @@ func describeStruct(cfg *frozenConfig, typ reflect.Type) (*StructDescriptor, err
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
for _, binding := range structDescriptor.Fields {
|
for _, binding := range structDescriptor.Fields {
|
||||||
|
binding.levels = append([]int{i}, binding.levels...)
|
||||||
binding.Encoder = &structFieldEncoder{&field, binding.Encoder, false}
|
binding.Encoder = &structFieldEncoder{&field, binding.Encoder, false}
|
||||||
binding.Decoder = &structFieldDecoder{&field, binding.Decoder}
|
binding.Decoder = &structFieldDecoder{&field, binding.Decoder}
|
||||||
if field.Offset == 0 {
|
if field.Offset == 0 {
|
||||||
@ -221,12 +223,11 @@ func describeStruct(cfg *frozenConfig, typ reflect.Type) (*StructDescriptor, err
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
for _, binding := range structDescriptor.Fields {
|
for _, binding := range structDescriptor.Fields {
|
||||||
cloneField := field
|
binding.levels = append([]int{i}, binding.levels...)
|
||||||
cloneField.Name = binding.Field.Name
|
|
||||||
binding.Encoder = &optionalEncoder{binding.Encoder}
|
binding.Encoder = &optionalEncoder{binding.Encoder}
|
||||||
binding.Encoder = &structFieldEncoder{&cloneField, binding.Encoder, false}
|
binding.Encoder = &structFieldEncoder{&field, binding.Encoder, false}
|
||||||
binding.Decoder = &deferenceDecoder{field.Type.Elem(), binding.Decoder}
|
binding.Decoder = &deferenceDecoder{field.Type.Elem(), binding.Decoder}
|
||||||
binding.Decoder = &structFieldDecoder{&cloneField, binding.Decoder}
|
binding.Decoder = &structFieldDecoder{&field, binding.Decoder}
|
||||||
if field.Offset == 0 {
|
if field.Offset == 0 {
|
||||||
headAnonymousBindings = append(headAnonymousBindings, binding)
|
headAnonymousBindings = append(headAnonymousBindings, binding)
|
||||||
} else {
|
} else {
|
||||||
@ -266,6 +267,7 @@ func describeStruct(cfg *frozenConfig, typ reflect.Type) (*StructDescriptor, err
|
|||||||
Decoder: decoder,
|
Decoder: decoder,
|
||||||
Encoder: encoder,
|
Encoder: encoder,
|
||||||
}
|
}
|
||||||
|
binding.levels = []int{i}
|
||||||
bindings = append(bindings, binding)
|
bindings = append(bindings, binding)
|
||||||
}
|
}
|
||||||
return createStructDescriptor(cfg, typ, bindings, headAnonymousBindings, tailAnonymousBindings), nil
|
return createStructDescriptor(cfg, typ, bindings, headAnonymousBindings, tailAnonymousBindings), nil
|
||||||
|
@ -8,48 +8,102 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
func encoderOfStruct(cfg *frozenConfig, typ reflect.Type) (ValEncoder, error) {
|
func encoderOfStruct(cfg *frozenConfig, typ reflect.Type) (ValEncoder, error) {
|
||||||
fieldsByToName := map[string]int{}
|
type bindingTo struct {
|
||||||
orderedFields := []*structFieldTo{}
|
binding *Binding
|
||||||
|
toName string
|
||||||
|
ignored bool
|
||||||
|
}
|
||||||
|
orderedBindings := []*bindingTo{}
|
||||||
structDescriptor, err := describeStruct(cfg, typ)
|
structDescriptor, err := describeStruct(cfg, typ)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
for index, binding := range structDescriptor.Fields {
|
for _, binding := range structDescriptor.Fields {
|
||||||
for _, toName := range binding.ToNames {
|
for _, toName := range binding.ToNames {
|
||||||
oldIndex, found := fieldsByToName[toName]
|
new := &bindingTo{
|
||||||
if found {
|
binding: binding,
|
||||||
orderedFields[oldIndex] = nil // replaced by the later one
|
toName: toName,
|
||||||
}
|
}
|
||||||
fieldsByToName[toName] = index
|
for _, old := range orderedBindings {
|
||||||
orderedFields = append(orderedFields, &structFieldTo{
|
if old.toName != toName {
|
||||||
binding.Encoder.(*structFieldEncoder),
|
continue
|
||||||
toName,
|
}
|
||||||
})
|
old.ignored, new.ignored = resolveConflictBinding(old.binding, new.binding)
|
||||||
|
}
|
||||||
|
orderedBindings = append(orderedBindings, new)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if len(orderedFields) == 0 {
|
if len(orderedBindings) == 0 {
|
||||||
return &emptyStructEncoder{}, nil
|
return &emptyStructEncoder{}, nil
|
||||||
}
|
}
|
||||||
finalOrderedFields := []structFieldTo{}
|
finalOrderedFields := []structFieldTo{}
|
||||||
for _, structFieldTo := range orderedFields {
|
for _, bindingTo := range orderedBindings {
|
||||||
if structFieldTo != nil {
|
if !bindingTo.ignored {
|
||||||
finalOrderedFields = append(finalOrderedFields, *structFieldTo)
|
finalOrderedFields = append(finalOrderedFields, structFieldTo{
|
||||||
|
encoder: bindingTo.binding.Encoder.(*structFieldEncoder),
|
||||||
|
toName: bindingTo.toName,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return &structEncoder{structDescriptor.onePtrEmbedded, structDescriptor.onePtrOptimization, finalOrderedFields}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func resolveConflictBinding(old, new *Binding) (ignoreOld, ignoreNew bool) {
|
||||||
|
newTagged := new.Field.Tag.Get("json") != ""
|
||||||
|
oldTagged := old.Field.Tag.Get("json") != ""
|
||||||
|
if newTagged {
|
||||||
|
if oldTagged {
|
||||||
|
if len(old.levels) > len(new.levels) {
|
||||||
|
return true, false
|
||||||
|
} else if len(new.levels) > len(old.levels) {
|
||||||
|
return false, true
|
||||||
|
} else {
|
||||||
|
return true, true
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return true, false
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if oldTagged {
|
||||||
|
return true, false
|
||||||
|
} else {
|
||||||
|
if len(old.levels) > len(new.levels) {
|
||||||
|
return true, false
|
||||||
|
} else if len(new.levels) > len(old.levels) {
|
||||||
|
return false, true
|
||||||
|
} else {
|
||||||
|
return true, true
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return &structEncoder{structDescriptor.onePtrEmbedded,structDescriptor.onePtrOptimization,finalOrderedFields}, nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func decoderOfStruct(cfg *frozenConfig, typ reflect.Type) (ValDecoder, error) {
|
func decoderOfStruct(cfg *frozenConfig, typ reflect.Type) (ValDecoder, error) {
|
||||||
fields := map[string]*structFieldDecoder{}
|
bindings := map[string]*Binding{}
|
||||||
structDescriptor, err := describeStruct(cfg, typ)
|
structDescriptor, err := describeStruct(cfg, typ)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
for _, binding := range structDescriptor.Fields {
|
for _, binding := range structDescriptor.Fields {
|
||||||
for _, fromName := range binding.FromNames {
|
for _, fromName := range binding.FromNames {
|
||||||
fields[fromName] = binding.Decoder.(*structFieldDecoder)
|
old := bindings[fromName]
|
||||||
|
if old == nil {
|
||||||
|
bindings[fromName] = binding
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
ignoreOld, ignoreNew := resolveConflictBinding(old, binding)
|
||||||
|
if ignoreOld {
|
||||||
|
delete(bindings, fromName)
|
||||||
|
}
|
||||||
|
if !ignoreNew {
|
||||||
|
bindings[fromName] = binding
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
fields := map[string]*structFieldDecoder{}
|
||||||
|
for k, binding := range bindings {
|
||||||
|
fields[k] = binding.Decoder.(*structFieldDecoder)
|
||||||
|
}
|
||||||
return createStructDecoder(typ, fields)
|
return createStructDecoder(typ, fields)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -120,7 +174,7 @@ func createStructDecoder(typ reflect.Type, fields map[string]*structFieldDecoder
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
return &threeFieldsStructDecoder{typ,
|
return &threeFieldsStructDecoder{typ,
|
||||||
fieldName1, fieldDecoder1, fieldName2, fieldDecoder2, fieldName3, fieldDecoder3}, nil
|
fieldName1, fieldDecoder1, fieldName2, fieldDecoder2, fieldName3, fieldDecoder3}, nil
|
||||||
case 4:
|
case 4:
|
||||||
var fieldName1 int32
|
var fieldName1 int32
|
||||||
var fieldName2 int32
|
var fieldName2 int32
|
||||||
@ -153,8 +207,8 @@ func createStructDecoder(typ reflect.Type, fields map[string]*structFieldDecoder
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
return &fourFieldsStructDecoder{typ,
|
return &fourFieldsStructDecoder{typ,
|
||||||
fieldName1, fieldDecoder1, fieldName2, fieldDecoder2, fieldName3, fieldDecoder3,
|
fieldName1, fieldDecoder1, fieldName2, fieldDecoder2, fieldName3, fieldDecoder3,
|
||||||
fieldName4, fieldDecoder4}, nil
|
fieldName4, fieldDecoder4}, nil
|
||||||
case 5:
|
case 5:
|
||||||
var fieldName1 int32
|
var fieldName1 int32
|
||||||
var fieldName2 int32
|
var fieldName2 int32
|
||||||
@ -192,8 +246,8 @@ func createStructDecoder(typ reflect.Type, fields map[string]*structFieldDecoder
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
return &fiveFieldsStructDecoder{typ,
|
return &fiveFieldsStructDecoder{typ,
|
||||||
fieldName1, fieldDecoder1, fieldName2, fieldDecoder2, fieldName3, fieldDecoder3,
|
fieldName1, fieldDecoder1, fieldName2, fieldDecoder2, fieldName3, fieldDecoder3,
|
||||||
fieldName4, fieldDecoder4, fieldName5, fieldDecoder5}, nil
|
fieldName4, fieldDecoder4, fieldName5, fieldDecoder5}, nil
|
||||||
case 6:
|
case 6:
|
||||||
var fieldName1 int32
|
var fieldName1 int32
|
||||||
var fieldName2 int32
|
var fieldName2 int32
|
||||||
@ -236,8 +290,8 @@ func createStructDecoder(typ reflect.Type, fields map[string]*structFieldDecoder
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
return &sixFieldsStructDecoder{typ,
|
return &sixFieldsStructDecoder{typ,
|
||||||
fieldName1, fieldDecoder1, fieldName2, fieldDecoder2, fieldName3, fieldDecoder3,
|
fieldName1, fieldDecoder1, fieldName2, fieldDecoder2, fieldName3, fieldDecoder3,
|
||||||
fieldName4, fieldDecoder4, fieldName5, fieldDecoder5, fieldName6, fieldDecoder6}, nil
|
fieldName4, fieldDecoder4, fieldName5, fieldDecoder5, fieldName6, fieldDecoder6}, nil
|
||||||
case 7:
|
case 7:
|
||||||
var fieldName1 int32
|
var fieldName1 int32
|
||||||
var fieldName2 int32
|
var fieldName2 int32
|
||||||
@ -285,9 +339,9 @@ func createStructDecoder(typ reflect.Type, fields map[string]*structFieldDecoder
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
return &sevenFieldsStructDecoder{typ,
|
return &sevenFieldsStructDecoder{typ,
|
||||||
fieldName1, fieldDecoder1, fieldName2, fieldDecoder2, fieldName3, fieldDecoder3,
|
fieldName1, fieldDecoder1, fieldName2, fieldDecoder2, fieldName3, fieldDecoder3,
|
||||||
fieldName4, fieldDecoder4, fieldName5, fieldDecoder5, fieldName6, fieldDecoder6,
|
fieldName4, fieldDecoder4, fieldName5, fieldDecoder5, fieldName6, fieldDecoder6,
|
||||||
fieldName7, fieldDecoder7}, nil
|
fieldName7, fieldDecoder7}, nil
|
||||||
case 8:
|
case 8:
|
||||||
var fieldName1 int32
|
var fieldName1 int32
|
||||||
var fieldName2 int32
|
var fieldName2 int32
|
||||||
@ -340,9 +394,9 @@ func createStructDecoder(typ reflect.Type, fields map[string]*structFieldDecoder
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
return &eightFieldsStructDecoder{typ,
|
return &eightFieldsStructDecoder{typ,
|
||||||
fieldName1, fieldDecoder1, fieldName2, fieldDecoder2, fieldName3, fieldDecoder3,
|
fieldName1, fieldDecoder1, fieldName2, fieldDecoder2, fieldName3, fieldDecoder3,
|
||||||
fieldName4, fieldDecoder4, fieldName5, fieldDecoder5, fieldName6, fieldDecoder6,
|
fieldName4, fieldDecoder4, fieldName5, fieldDecoder5, fieldName6, fieldDecoder6,
|
||||||
fieldName7, fieldDecoder7, fieldName8, fieldDecoder8}, nil
|
fieldName7, fieldDecoder7, fieldName8, fieldDecoder8}, nil
|
||||||
case 9:
|
case 9:
|
||||||
var fieldName1 int32
|
var fieldName1 int32
|
||||||
var fieldName2 int32
|
var fieldName2 int32
|
||||||
@ -400,9 +454,9 @@ func createStructDecoder(typ reflect.Type, fields map[string]*structFieldDecoder
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
return &nineFieldsStructDecoder{typ,
|
return &nineFieldsStructDecoder{typ,
|
||||||
fieldName1, fieldDecoder1, fieldName2, fieldDecoder2, fieldName3, fieldDecoder3,
|
fieldName1, fieldDecoder1, fieldName2, fieldDecoder2, fieldName3, fieldDecoder3,
|
||||||
fieldName4, fieldDecoder4, fieldName5, fieldDecoder5, fieldName6, fieldDecoder6,
|
fieldName4, fieldDecoder4, fieldName5, fieldDecoder5, fieldName6, fieldDecoder6,
|
||||||
fieldName7, fieldDecoder7, fieldName8, fieldDecoder8, fieldName9, fieldDecoder9}, nil
|
fieldName7, fieldDecoder7, fieldName8, fieldDecoder8, fieldName9, fieldDecoder9}, nil
|
||||||
case 10:
|
case 10:
|
||||||
var fieldName1 int32
|
var fieldName1 int32
|
||||||
var fieldName2 int32
|
var fieldName2 int32
|
||||||
@ -465,10 +519,10 @@ func createStructDecoder(typ reflect.Type, fields map[string]*structFieldDecoder
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
return &tenFieldsStructDecoder{typ,
|
return &tenFieldsStructDecoder{typ,
|
||||||
fieldName1, fieldDecoder1, fieldName2, fieldDecoder2, fieldName3, fieldDecoder3,
|
fieldName1, fieldDecoder1, fieldName2, fieldDecoder2, fieldName3, fieldDecoder3,
|
||||||
fieldName4, fieldDecoder4, fieldName5, fieldDecoder5, fieldName6, fieldDecoder6,
|
fieldName4, fieldDecoder4, fieldName5, fieldDecoder5, fieldName6, fieldDecoder6,
|
||||||
fieldName7, fieldDecoder7, fieldName8, fieldDecoder8, fieldName9, fieldDecoder9,
|
fieldName7, fieldDecoder7, fieldName8, fieldDecoder8, fieldName9, fieldDecoder9,
|
||||||
fieldName10, fieldDecoder10}, nil
|
fieldName10, fieldDecoder10}, nil
|
||||||
}
|
}
|
||||||
return &generalStructDecoder{typ, fields}, nil
|
return &generalStructDecoder{typ, fields}, nil
|
||||||
}
|
}
|
||||||
@ -992,9 +1046,9 @@ func (encoder *structFieldEncoder) IsEmpty(ptr unsafe.Pointer) bool {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type structEncoder struct {
|
type structEncoder struct {
|
||||||
onePtrEmbedded bool
|
onePtrEmbedded bool
|
||||||
onePtrOptimization bool
|
onePtrOptimization bool
|
||||||
fields []structFieldTo
|
fields []structFieldTo
|
||||||
}
|
}
|
||||||
|
|
||||||
type structFieldTo struct {
|
type structFieldTo struct {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user