Actually decode list of objects properly in JSON
This commit is contained in:
parent
65159dc252
commit
c6802d3070
47
decoder.go
47
decoder.go
@ -31,8 +31,8 @@ func DecodeObject(out interface{}, n *hcl.Object) error {
|
|||||||
return d.decode("root", n, reflect.ValueOf(out).Elem())
|
return d.decode("root", n, reflect.ValueOf(out).Elem())
|
||||||
}
|
}
|
||||||
|
|
||||||
type decoder struct{
|
type decoder struct {
|
||||||
last, current reflect.Kind
|
stack []reflect.Kind
|
||||||
}
|
}
|
||||||
|
|
||||||
func (d *decoder) decode(name string, o *hcl.Object, result reflect.Value) error {
|
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
|
// Push current onto stack unless it is an interface.
|
||||||
// some context to determine things.
|
if k.Kind() != reflect.Interface {
|
||||||
d.last = d.current
|
d.stack = append(d.stack, k.Kind())
|
||||||
d.current = k.Kind()
|
|
||||||
|
// Schedule a pop
|
||||||
|
defer func() {
|
||||||
|
d.stack = d.stack[:len(d.stack)-1]
|
||||||
|
}()
|
||||||
|
}
|
||||||
|
|
||||||
switch k.Kind() {
|
switch k.Kind() {
|
||||||
case reflect.Bool:
|
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
|
// If we're at the root or we're directly within a slice, then we
|
||||||
// decode objects into map[string]interface{}, otherwise we decode
|
// decode objects into map[string]interface{}, otherwise we decode
|
||||||
// them into lists.
|
// 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{}
|
var temp map[string]interface{}
|
||||||
tempVal := reflect.ValueOf(temp)
|
tempVal := reflect.ValueOf(temp)
|
||||||
result := reflect.MakeMap(
|
result := reflect.MakeMap(
|
||||||
@ -139,29 +144,11 @@ func (d *decoder) decodeInterface(name string, o *hcl.Object, result reflect.Val
|
|||||||
set = result
|
set = result
|
||||||
}
|
}
|
||||||
case hcl.ValueTypeList:
|
case hcl.ValueTypeList:
|
||||||
/*
|
var temp []interface{}
|
||||||
var temp []interface{}
|
tempVal := reflect.ValueOf(temp)
|
||||||
tempVal := reflect.ValueOf(temp)
|
result := reflect.MakeSlice(
|
||||||
result := reflect.MakeSlice(
|
reflect.SliceOf(tempVal.Type().Elem()), 0, 0)
|
||||||
reflect.SliceOf(tempVal.Type().Elem()), 0, 0)
|
set = result
|
||||||
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)
|
|
||||||
case hcl.ValueTypeBool:
|
case hcl.ValueTypeBool:
|
||||||
var result bool
|
var result bool
|
||||||
set = reflect.Indirect(reflect.New(reflect.TypeOf(result)))
|
set = reflect.Indirect(reflect.New(reflect.TypeOf(result)))
|
||||||
|
@ -115,7 +115,7 @@ func TestDecode_interface(t *testing.T) {
|
|||||||
"structure_list.json",
|
"structure_list.json",
|
||||||
false,
|
false,
|
||||||
map[string]interface{}{
|
map[string]interface{}{
|
||||||
"foo": []map[string]interface{}{
|
"foo": []interface{}{
|
||||||
map[string]interface{}{
|
map[string]interface{}{
|
||||||
"key": 7,
|
"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 {
|
for _, tc := range cases {
|
||||||
if tc.File != "empty.hcl" { continue }
|
|
||||||
d, err := ioutil.ReadFile(filepath.Join(fixtureDir, tc.File))
|
d, err := ioutil.ReadFile(filepath.Join(fixtureDir, tc.File))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("err: %s", err)
|
t.Fatalf("err: %s", err)
|
||||||
|
16
test-fixtures/structure_list_deep.json
Normal file
16
test-fixtures/structure_list_deep.json
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
{
|
||||||
|
"bar": {
|
||||||
|
"foo": {
|
||||||
|
"name": "terraform_example",
|
||||||
|
"ingress": [
|
||||||
|
{
|
||||||
|
"from_port": 22
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"from_port": 80
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue
Block a user