Skip to content

Commit da8ed78

Browse files
authored
Fix #124 - handle incoming JSON that is not stringified (cfn test doe… (#131)
* Fix #124 - handle incoming JSON that is not stringified (cfn test does not stringify JSON before passing to the handler * Add support for slices and maps (and pointers to them) to encoding.Unstringify
1 parent d8ba82c commit da8ed78

File tree

5 files changed

+529
-99
lines changed

5 files changed

+529
-99
lines changed

cfn/encoding/stringify.go

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -6,11 +6,6 @@ import (
66
"strings"
77
)
88

9-
var zeroValue reflect.Value
10-
11-
var stringType = reflect.TypeOf("")
12-
var interfaceType = reflect.TypeOf((*interface{})(nil)).Elem()
13-
149
func stringifyType(t reflect.Type) reflect.Type {
1510
switch t.Kind() {
1611
case reflect.Map:

cfn/encoding/unstringify.go

Lines changed: 204 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,210 @@ package encoding
33
import (
44
"fmt"
55
"reflect"
6+
"strconv"
67
"strings"
78
)
89

10+
func convertStruct(i interface{}, t reflect.Type, pointer bool) (reflect.Value, error) {
11+
m, ok := i.(map[string]interface{})
12+
if !ok {
13+
return zeroValue, fmt.Errorf("Cannot convert %T to struct", i)
14+
}
15+
16+
out := reflect.New(t)
17+
18+
err := Unstringify(m, out.Interface())
19+
if err != nil {
20+
return zeroValue, err
21+
}
22+
23+
if !pointer {
24+
out = out.Elem()
25+
}
26+
27+
return out, nil
28+
}
29+
30+
func convertSlice(i interface{}, t reflect.Type, pointer bool) (reflect.Value, error) {
31+
s, ok := i.([]interface{})
32+
if !ok {
33+
return zeroValue, fmt.Errorf("Cannot convert %T to slice", i)
34+
}
35+
36+
out := reflect.New(t)
37+
out.Elem().Set(reflect.MakeSlice(t, len(s), len(s)))
38+
39+
for j, v := range s {
40+
val, err := convertType(t.Elem(), v)
41+
if err != nil {
42+
return zeroValue, err
43+
}
44+
45+
out.Elem().Index(j).Set(val)
46+
}
47+
48+
if !pointer {
49+
out = out.Elem()
50+
}
51+
52+
return out, nil
53+
}
54+
55+
func convertMap(i interface{}, t reflect.Type, pointer bool) (reflect.Value, error) {
56+
m, ok := i.(map[string]interface{})
57+
if !ok {
58+
return zeroValue, fmt.Errorf("Cannot convert %T to map with string keys", i)
59+
}
60+
61+
out := reflect.New(t)
62+
out.Elem().Set(reflect.MakeMap(t))
63+
64+
for k, v := range m {
65+
val, err := convertType(t.Elem(), v)
66+
if err != nil {
67+
return zeroValue, err
68+
}
69+
70+
out.Elem().SetMapIndex(reflect.ValueOf(k), val)
71+
}
72+
73+
if !pointer {
74+
out = out.Elem()
75+
}
76+
77+
return out, nil
78+
}
79+
80+
func convertString(i interface{}, pointer bool) (reflect.Value, error) {
81+
s, ok := i.(string)
82+
83+
if !ok {
84+
return zeroValue, fmt.Errorf("Cannot convert %T to string", i)
85+
}
86+
87+
if pointer {
88+
return reflect.ValueOf(&s), nil
89+
}
90+
91+
return reflect.ValueOf(s), nil
92+
}
93+
94+
func convertBool(i interface{}, pointer bool) (reflect.Value, error) {
95+
var b bool
96+
var err error
97+
98+
switch v := i.(type) {
99+
case bool:
100+
b = v
101+
102+
case string:
103+
b, err = strconv.ParseBool(v)
104+
if err != nil {
105+
return zeroValue, err
106+
}
107+
108+
default:
109+
return zeroValue, fmt.Errorf("Cannot convert %T to bool", i)
110+
}
111+
112+
if pointer {
113+
return reflect.ValueOf(&b), nil
114+
}
115+
116+
return reflect.ValueOf(b), nil
117+
}
118+
119+
func convertInt(i interface{}, pointer bool) (reflect.Value, error) {
120+
var n int
121+
122+
switch v := i.(type) {
123+
case int:
124+
n = v
125+
126+
case float64:
127+
n = int(v)
128+
129+
case string:
130+
n64, err := strconv.ParseInt(v, 0, 32)
131+
if err != nil {
132+
return zeroValue, err
133+
}
134+
135+
n = int(n64)
136+
137+
default:
138+
return zeroValue, fmt.Errorf("Cannot convert %T to bool", i)
139+
}
140+
141+
if pointer {
142+
return reflect.ValueOf(&n), nil
143+
}
144+
145+
return reflect.ValueOf(n), nil
146+
}
147+
148+
func convertFloat64(i interface{}, pointer bool) (reflect.Value, error) {
149+
var f float64
150+
var err error
151+
152+
switch v := i.(type) {
153+
case float64:
154+
f = v
155+
156+
case int:
157+
f = float64(v)
158+
159+
case string:
160+
f, err = strconv.ParseFloat(v, 64)
161+
if err != nil {
162+
return zeroValue, err
163+
}
164+
165+
default:
166+
return zeroValue, fmt.Errorf("Cannot convert %T to bool", i)
167+
}
168+
169+
if pointer {
170+
return reflect.ValueOf(&f), nil
171+
}
172+
173+
return reflect.ValueOf(f), nil
174+
}
175+
176+
func convertType(t reflect.Type, i interface{}) (reflect.Value, error) {
177+
pointer := false
178+
if t.Kind() == reflect.Ptr {
179+
pointer = true
180+
t = t.Elem()
181+
}
182+
183+
switch t.Kind() {
184+
case reflect.Struct:
185+
return convertStruct(i, t, pointer)
186+
187+
case reflect.Slice:
188+
return convertSlice(i, t, pointer)
189+
190+
case reflect.Map:
191+
return convertMap(i, t, pointer)
192+
193+
case reflect.String:
194+
return convertString(i, pointer)
195+
196+
case reflect.Bool:
197+
return convertBool(i, pointer)
198+
199+
case reflect.Int:
200+
return convertInt(i, pointer)
201+
202+
case reflect.Float64:
203+
return convertFloat64(i, pointer)
204+
205+
default:
206+
return zeroValue, fmt.Errorf("Unsupported type %v", t)
207+
}
208+
}
209+
9210
// Unstringify takes a stringified representation of a value
10211
// and populates it into the supplied interface
11212
func Unstringify(data map[string]interface{}, v interface{}) error {
@@ -22,38 +223,10 @@ func Unstringify(data map[string]interface{}, v interface{}) error {
22223
jsonName = jsonTag[0]
23224
}
24225

25-
var newValue reflect.Value
26-
27226
if value, ok := data[jsonName]; ok {
28-
switch f.Type.Kind() {
29-
case reflect.Ptr:
30-
switch f.Type.Elem().Kind() {
31-
case reflect.String:
32-
newValue = toStringPtrValue(value.(string))
33-
case reflect.Bool:
34-
newValue = toBoolPtrValue(value.(string))
35-
case reflect.Int:
36-
newValue = toIntPtrValue(value.(string))
37-
case reflect.Float64:
38-
newValue = toFloat64PtrValue(value.(string))
39-
case reflect.Struct:
40-
newValue = reflect.New(f.Type.Elem())
41-
Unstringify(value.(map[string]interface{}), newValue.Interface())
42-
}
43-
case reflect.String:
44-
newValue = toStringValue(value.(string))
45-
case reflect.Bool:
46-
newValue = toBoolValue(value.(string))
47-
case reflect.Int:
48-
newValue = toIntValue(value.(string))
49-
case reflect.Float64:
50-
newValue = toFloat64Value(value.(string))
51-
case reflect.Struct:
52-
newValue = reflect.New(f.Type)
53-
Unstringify(value.(map[string]interface{}), newValue.Interface())
54-
newValue = newValue.Elem()
55-
default:
56-
return fmt.Errorf("Unsupported type: '%v'", f.Type)
227+
newValue, err := convertType(f.Type, value)
228+
if err != nil {
229+
return err
57230
}
58231

59232
val.FieldByName(f.Name).Set(newValue)

0 commit comments

Comments
 (0)