Actually decode list of objects properly in JSON

This commit is contained in:
Mitchell Hashimoto 2014-08-21 14:02:29 -07:00
parent 65159dc252
commit c6802d3070
3 changed files with 57 additions and 32 deletions

View File

@ -31,8 +31,8 @@ func DecodeObject(out interface{}, n *hcl.Object) error {
return d.decode("root", n, reflect.ValueOf(out).Elem())
}
type decoder struct{
last, current reflect.Kind
type decoder struct {
stack []reflect.Kind
}
func (d *decoder) decode(name string, o *hcl.Object, result reflect.Value) error {
@ -47,10 +47,15 @@ func (d *decoder) decode(name string, o *hcl.Object, result reflect.Value) error
}
}
// Keep track of the last known type and the current since we use
// some context to determine things.
d.last = d.current
d.current = k.Kind()
// Push current onto stack unless it is an interface.
if k.Kind() != reflect.Interface {
d.stack = append(d.stack, k.Kind())
// Schedule a pop
defer func() {
d.stack = d.stack[:len(d.stack)-1]
}()
}
switch k.Kind() {
case reflect.Bool:
@ -122,7 +127,7 @@ func (d *decoder) decodeInterface(name string, o *hcl.Object, result reflect.Val
// If we're at the root or we're directly within a slice, then we
// decode objects into map[string]interface{}, otherwise we decode
// them into lists.
if d.last == reflect.Invalid || d.last == reflect.Slice {
if len(d.stack) == 0 || d.stack[len(d.stack)-1] == reflect.Slice {
var temp map[string]interface{}
tempVal := reflect.ValueOf(temp)
result := reflect.MakeMap(
@ -139,29 +144,11 @@ func (d *decoder) decodeInterface(name string, o *hcl.Object, result reflect.Val
set = result
}
case hcl.ValueTypeList:
/*
var temp []interface{}
tempVal := reflect.ValueOf(temp)
result := reflect.MakeSlice(
reflect.SliceOf(tempVal.Type().Elem()), 0, 0)
set = result
*/
redecode = false
list := o.Value.([]*hcl.Object)
result := make([]interface{}, 0, len(list))
for _, elem := range list {
raw := new(interface{})
err := d.decode(
name, elem, reflect.Indirect(reflect.ValueOf(raw)))
if err != nil {
return err
}
result = append(result, *raw)
}
set = reflect.ValueOf(result)
var temp []interface{}
tempVal := reflect.ValueOf(temp)
result := reflect.MakeSlice(
reflect.SliceOf(tempVal.Type().Elem()), 0, 0)
set = result
case hcl.ValueTypeBool:
var result bool
set = reflect.Indirect(reflect.New(reflect.TypeOf(result)))

View File

@ -115,7 +115,7 @@ func TestDecode_interface(t *testing.T) {
"structure_list.json",
false,
map[string]interface{}{
"foo": []map[string]interface{}{
"foo": []interface{}{
map[string]interface{}{
"key": 7,
},
@ -125,10 +125,32 @@ func TestDecode_interface(t *testing.T) {
},
},
},
{
"structure_list_deep.json",
false,
map[string]interface{}{
"bar": []map[string]interface{}{
map[string]interface{}{
"foo": []map[string]interface{}{
map[string]interface{}{
"name": "terraform_example",
"ingress": []interface{}{
map[string]interface{}{
"from_port": 22,
},
map[string]interface{}{
"from_port": 80,
},
},
},
},
},
},
},
},
}
for _, tc := range cases {
if tc.File != "empty.hcl" { continue }
d, err := ioutil.ReadFile(filepath.Join(fixtureDir, tc.File))
if err != nil {
t.Fatalf("err: %s", err)

View File

@ -0,0 +1,16 @@
{
"bar": {
"foo": {
"name": "terraform_example",
"ingress": [
{
"from_port": 22
},
{
"from_port": 80
}
]
}
}
}