I have unusual task: 1. parse json message to Go struct 2. verify that all fields in JSON are within specific limits: - string fields length no longer fixed constant - maps contain no more than fixed number elements - if values of map keys are nested structs verify for above 2 rules
To do this I use reflect, then iterating over elements, and doing type checking: - if int or float - nothing to do - no verification - if string - verify length (and return if failed) - if map verify map length (and return if failed), then iterate over map values and recursively check if their fields violate string/map rules - default (I assume that this is struct nested JSON structure): convert it to interface slice and do recursive call.
Problem: In JSON, I would have different map value types like: - map[string]MyStruct1 - map[string]MyStruct2 - etc.
So when I'm doing type checking I write: case map[string]interface{}
But in my program this case is never matched and goes to case default, causing some error.
Any possible way to match type with case - map[string]interface{} ????
Here is my code for reference: http://play.golang.org/p/IVXHLBRuPK
func validate(vals []interface{}) bool {
result := true
for _, elem := range vals {
switch v := elem.(type) {
case int, float64:
fmt.Println("Got int or float: ", v)
case string:
fmt.Println("Got string", v)
if len(elem.(string)) > 5 {
fmt.Println("String rule Violation!")
result = false
break
fmt.Println("After Break")
}
case map[string]interface{}:
fmt.Println("Got map", v)
if len(elem.(map[string]interface{})) > 1 || !validate(elem.([]interface{})) {
fmt.Println("Map length rule Violation!")
result = false
break
}
default:
fmt.Println("Got struct:", v)
// Convert to interface list all other structures no string/int/float/map:
new_v := reflect.ValueOf(elem)
new_values := make([]interface{}, new_v.NumField())
for j := 0; j < new_v.NumField(); j++ {
new_values[j] = new_v.Field(j).Interface()
}
// Recursively call for validate nested structs
if !validate(new_values) {
result = false
break
}
}
}
fmt.Println("After Break 2")
return result
}
func main() {
// Test truct:
x := C{1, B{"abc", A{10, 0.1, map[string]Host{"1,2,3,4": Host{"1.2.3.4"}}}}}
// Conversion:
v := reflect.ValueOf(x)
values := make([]interface{}, v.NumField())
for i := 0; i < v.NumField(); i++ {
values[i] = v.Field(i).Interface()
}
// Validate function verification
fmt.Println(validate(values))
}
In this example I can't ever reach case: map[string]interface{}
Big kudos on helpful suggestions!
The problem is case map[string]interface{}
won't match map[string]Host
so it will get parsed as a struct, which it isn't.
You will either have to check new_v.Kind()
and handle maps via reflection or add a special case for map[string]Host
.