Skip to content

Instantly share code, notes, and snippets.

@mjhuber
Created December 20, 2019 20:48
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save mjhuber/2cd02a9014cba3c3d407f71440b452f1 to your computer and use it in GitHub Desktop.
Save mjhuber/2cd02a9014cba3c3d407f71440b452f1 to your computer and use it in GitHub Desktop.
Traverse a nested object by yaml/json tags
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