Skip to content

Commit bdd9344

Browse files
committedSep 16, 2016
Simplify the code to expand objects
Now that we know only individual items in a slice need to be expanded, we can simplify the code flow to expand the ast in place while decoding.
1 parent 769aa72 commit bdd9344

File tree

2 files changed

+93
-71
lines changed

2 files changed

+93
-71
lines changed
 

‎decoder.go

Lines changed: 35 additions & 71 deletions
Original file line numberDiff line numberDiff line change
@@ -418,20 +418,6 @@ func (d *decoder) decodeSlice(name string, node ast.Node, result reflect.Value)
418418
resultSliceType, 0, 0)
419419
}
420420

421-
// if node is an object that was decoded from ambiguous JSON and flattened
422-
// as a list, decode into a single value in the slice.
423-
if objAsList(node, resultElemType) {
424-
val := reflect.Indirect(reflect.New(resultElemType))
425-
err := d.decodeFlatObj(name+"[0]", node, val)
426-
if err != nil {
427-
return err
428-
}
429-
430-
result = reflect.Append(result, val)
431-
set.Set(result)
432-
return nil
433-
}
434-
435421
// Figure out the items we'll be copying into the slice
436422
var items []ast.Node
437423
switch n := node.(type) {
@@ -456,6 +442,12 @@ func (d *decoder) decodeSlice(name string, node ast.Node, result reflect.Value)
456442

457443
// Decode
458444
val := reflect.Indirect(reflect.New(resultElemType))
445+
446+
// if item is an object that was decoded from ambiguous JSON and
447+
// flattened, make sure it's expanded if it needs to decode into a
448+
// defined structure.
449+
item := expandObject(item, val)
450+
459451
if err := d.decode(fieldName, item, val); err != nil {
460452
return err
461453
}
@@ -468,83 +460,55 @@ func (d *decoder) decodeSlice(name string, node ast.Node, result reflect.Value)
468460
return nil
469461
}
470462

471-
// decode a flattened object into a single struct
472-
func (d decoder) decodeFlatObj(name string, node ast.Node, result reflect.Value) error {
473-
list := node.(*ast.ObjectList)
474-
var keyToken token.Token
475-
// get the key token, and strip it out of the key-val nodes
476-
for _, item := range list.Items {
477-
keyToken = item.Keys[0].Token
478-
item.Keys = item.Keys[1:]
479-
}
480-
481-
// we need to un-flatten the ast enough to decode
482-
newNode := &ast.ObjectItem{
483-
Keys: []*ast.ObjectKey{
484-
&ast.ObjectKey{
485-
Token: keyToken,
486-
},
487-
},
488-
Val: &ast.ObjectType{
489-
List: list,
490-
},
491-
}
492-
493-
if err := d.decode(name, newNode, result); err != nil {
494-
return err
495-
}
496-
497-
return nil
498-
}
499-
500-
// objAsList detects if an ambiguous JSON object was flattened to a List which
501-
// should be decoded into a struct.
502-
func objAsList(node ast.Node, elemType reflect.Type) bool {
503-
objList, ok := node.(*ast.ObjectList)
463+
// expandObject detects if an ambiguous JSON object was flattened to a List which
464+
// should be decoded into a struct, and expands the ast to properly deocode.
465+
func expandObject(node ast.Node, result reflect.Value) ast.Node {
466+
item, ok := node.(*ast.ObjectItem)
504467
if !ok {
505-
return false
468+
return node
506469
}
507470

471+
elemType := result.Type()
472+
508473
// our target type must be a struct
509474
switch elemType.Kind() {
510475
case reflect.Ptr:
511476
switch elemType.Elem().Kind() {
512477
case reflect.Struct:
513478
//OK
514479
default:
515-
return false
480+
return node
516481
}
517482
case reflect.Struct:
518483
//OK
519484
default:
520-
return false
485+
return node
521486
}
522487

523-
fieldNames := make(map[string]bool)
524-
prevKey := ""
525-
526-
for _, item := range objList.Items {
527-
// a list value will have a key and field name
528-
if len(item.Keys) != 2 {
529-
return false
530-
}
531-
532-
key := item.Keys[0].Token.Value().(string)
533-
if prevKey != "" && key != prevKey {
534-
// the same object will have all the same key
535-
return false
536-
}
537-
prevKey = key
488+
// A list value will have a key and field name. If it had more fields,
489+
// it wouldn't have been flattened.
490+
if len(item.Keys) != 2 {
491+
return node
492+
}
538493

539-
fieldName := item.Keys[1].Token.Value().(string)
494+
keyToken := item.Keys[0].Token
495+
item.Keys = item.Keys[1:]
540496

541-
if ok := fieldNames[fieldName]; ok {
542-
// A single struct won't have duplicate fields.
543-
return false
544-
}
497+
// we need to un-flatten the ast enough to decode
498+
newNode := &ast.ObjectItem{
499+
Keys: []*ast.ObjectKey{
500+
&ast.ObjectKey{
501+
Token: keyToken,
502+
},
503+
},
504+
Val: &ast.ObjectType{
505+
List: &ast.ObjectList{
506+
Items: []*ast.ObjectItem{item},
507+
},
508+
},
545509
}
546510

547-
return true
511+
return newNode
548512
}
549513

550514
func (d *decoder) decodeString(name string, node ast.Node, result reflect.Value) error {

‎decoder_test.go

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1016,6 +1016,64 @@ func TestDecode_flattenedJSON(t *testing.T) {
10161016
},
10171017
},
10181018
},
1019+
1020+
{ // Nested objects, one with a sibling key, and one without
1021+
JSON: `
1022+
{
1023+
"variable": {
1024+
"var_1": {
1025+
"default": {
1026+
"key1": "a",
1027+
"key2": "b"
1028+
}
1029+
},
1030+
"var_2": {
1031+
"description": "Described",
1032+
"default": {
1033+
"key1": "a",
1034+
"key2": "b"
1035+
}
1036+
}
1037+
}
1038+
}
1039+
`,
1040+
Out: &[]map[string]interface{}{},
1041+
Expected: &[]map[string]interface{}{
1042+
{
1043+
"variable": []map[string]interface{}{
1044+
{
1045+
"var_1": []map[string]interface{}{
1046+
{
1047+
"default": []map[string]interface{}{
1048+
{
1049+
"key1": "a",
1050+
"key2": "b",
1051+
},
1052+
},
1053+
},
1054+
},
1055+
},
1056+
},
1057+
},
1058+
{
1059+
"variable": []map[string]interface{}{
1060+
{
1061+
"var_2": []map[string]interface{}{
1062+
{
1063+
"description": "Described",
1064+
"default": []map[string]interface{}{
1065+
{
1066+
"key1": "a",
1067+
"key2": "b",
1068+
},
1069+
},
1070+
},
1071+
},
1072+
},
1073+
},
1074+
},
1075+
},
1076+
},
10191077
}
10201078

10211079
for i, tc := range cases {

0 commit comments

Comments
 (0)