Created
December 20, 2019 20:48
-
-
Save mjhuber/2cd02a9014cba3c3d407f71440b452f1 to your computer and use it in GitHub Desktop.
Traverse a nested object by yaml/json tags
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package main | |
import ( | |
"fmt" | |
"reflect" | |
"regexp" | |
"strings" | |
) | |
type Monitor struct { | |
Id int `json:"id"` | |
Name string `json:"name"` | |
Thresholds Threshold `json:"thresholds,omitempty"` | |
TestBool bool `json:"testBool,omitempty"` | |
} | |
type Threshold struct { | |
Critical int `json:"critical"` | |
Warning int `json:"warning"` | |
} | |
func setProperty(name string, obj interface{}, val interface{}) { | |
parts := strings.Split(name,".") | |
parent := reflect.ValueOf(obj) | |
for i, field := range parts { | |
current := getReflectedField(field,parent) | |
if i == len(parts)-1{ | |
// reached the final object - set the value | |
v := reflect.Indirect(current) | |
switch v.Kind() { | |
case reflect.Int: | |
num, ok := val.(int) | |
if ok { | |
v.SetInt(int64(num)) | |
} | |
case reflect.String: | |
str, ok := val.(string) | |
if ok { | |
v.SetString(str) | |
} | |
case reflect.Bool: | |
b, ok := val.(bool) | |
if ok { | |
v.SetBool(b) | |
} | |
} | |
} else { | |
parent = current | |
} | |
} | |
} | |
func getReflectedField(name string, v reflect.Value) reflect.Value { | |
r := v.Elem() | |
for i := 0; i < r.NumField(); i++ { | |
fName := r.Type().Field(i).Name | |
tags := r.Type().Field(i).Tag | |
if matches(fName,name,string(tags)) { | |
// it's the field we want | |
v = reflect.Indirect(v) | |
return v.Field(i).Addr() | |
} | |
} | |
return reflect.Value{} | |
} | |
// returns true if fieldName either matches the name of the field of the json/yaml tags match | |
func matches(fieldName string, desiredName string, tags string) bool { | |
if strings.ToLower(fieldName) == strings.ToLower(desiredName) { | |
return true | |
} | |
// check json/yaml field name | |
var re = regexp.MustCompile(`(?m)(json|yaml):\"[a-zA-Z]+(,.+|\")`) | |
return re.MatchString(desiredName) | |
} | |
func main() { | |
monitor := Monitor{ | |
Id: 3, | |
Name: "TestMonitor", | |
Thresholds: Threshold{ | |
Warning: 2, | |
Critical: 4, | |
}, | |
TestBool: false, | |
} | |
mynum := 500 | |
setProperty("thresholds.critical",&monitor,mynum) | |
setProperty("name",&monitor,"IHateReflection") | |
fmt.Printf("%+v\n",monitor) | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment