Skip to content

sunfmin/reflectutils

Repository files navigation

reflectutils

reflectutils is for setting your struct value by using string name and path that follows reflectutils rules.

The rules

  • .Name to set a property by field name
  • .Person.Name to set the name of the current property
  • .Person.Addresses[0].Phone to set an element of an array property
  • .Person.Addresses[].Name it will create a object of address and set it's property
  • .Person.MapData.Name it can also set value to map

How to install

go get github.com/sunfmin/reflectutils

By given these structs

	type Person struct {
	    Name        string
	    Score       float64
	    Gender      int
	    Company     *Company
	    Departments []*Department
	    Projects    []Project
	    Phones      map[string]string
	    Languages   map[string]Language
	}
	
	type Language struct {
	    Code string
	    Name string
	}
	
	type Company struct {
	    Name   string
	    Phone  *Phone
	    Phone2 **Phone
	}
	
	type Department struct {
	    Id   int
	    Name string
	}
	
	type Project struct {
	    Id      string
	    Name    string
	    Members []*Person
	}
	
	type Phone struct {
	    Number string
	}

For How to set simple field

	var p *Person
	Set(&p, "Name", "Felix")
	Set(&p, "Score", 66.88)
	Set(&p, "Gender", 1)
	printJsonV(p)
	fmt.Println(MustGet(&p, "Score"))
	//Output:
	// {
	// 	"Name": "Felix",
	// 	"Score": 66.88,
	// 	"Gender": 1,
	// 	"Company": null,
	// 	"Departments": null,
	// 	"Projects": null,
	// 	"Phones": null,
	// 	"Languages": null
	// }
	// 66.88

For how to set a struct property

	p := &Person{}
	Set(p, ".Company.Name", "The Plant")
	Set(p, ".Company.Phone.Number", "911")
	printJsonV(p)
	fmt.Println(MustGet(&p, ".Company.Phone.Number"))
	
	//Output:
	// {
	// 	"Name": "",
	// 	"Score": 0,
	// 	"Gender": 0,
	// 	"Company": {
	// 		"Name": "The Plant",
	// 		"Phone": {
	// 			"Number": "911"
	// 		}
	// 	},
	// 	"Departments": null,
	// 	"Projects": null,
	// 	"Phones": null,
	// 	"Languages": null
	// }
	// 911

For how to set slice and it's property

	var p *Person
	Set(&p, "Departments[0].Id", 1)
	Set(&p, "Departments[0].Name", "High Tech")
	Set(&p, "Projects[0].Name", "UIBuilder")
	// if you jump the index for an array, It will put nil in between
	// So there will be no index out of range error.
	Set(&p, "Departments[3].Id", 1)
	Set(&p, "Departments[3].Name", "High Tech")
	printJsonV(p)
	
	fmt.Println(MustGet(&p, "Departments[3].Name"))
	fmt.Println(MustGet(&p, "Departments[4].Name"))
	fmt.Println(MustGet(&p, "Projects[0].Name"))
	
	//Output:
	// {
	// 	"Name": "",
	// 	"Score": 0,
	// 	"Gender": 0,
	// 	"Company": null,
	// 	"Departments": [
	// 		{
	// 			"Id": 1,
	// 			"Name": "High Tech"
	// 		},
	// 		null,
	// 		null,
	// 		{
	// 			"Id": 1,
	// 			"Name": "High Tech"
	// 		}
	// 	],
	// 	"Projects": [
	// 		{
	// 			"Id": "",
	// 			"Name": "UIBuilder",
	// 			"Members": null
	// 		}
	// 	],
	// 	"Phones": null,
	// 	"Languages": null
	// }
	// High Tech
	// <nil>
	// UIBuilder

For how to set map property

	var p *Person
	Set(&p, "Languages.en_US.Name", "United States")
	Set(&p, "Languages.en_US.Code", "en_US")
	Set(&p, "Languages.zh_CN.Name", "China")
	Set(&p, "Languages.zh_CN.Code", "zh_CN")
	
	printJsonV(p)
	fmt.Println(MustGet(&p, "Languages.zh_CN.Code"))
	
	//Output:
	// {
	// 	"Name": "",
	// 	"Score": 0,
	// 	"Gender": 0,
	// 	"Company": null,
	// 	"Departments": null,
	// 	"Projects": null,
	// 	"Phones": null,
	// 	"Languages": {
	// 		"en_US": {
	// 			"Code": "en_US",
	// 			"Name": "United States"
	// 		},
	// 		"zh_CN": {
	// 			"Code": "zh_CN",
	// 			"Name": "China"
	// 		}
	// 	}
	// }
	// zh_CN

You can do whatever deeper you like

	var p *Person
	Set(&p, "Projects[0].Members[0].Company.Phone.Number", "911")
	
	printJsonV(p)
	fmt.Println(MustGet(&p, "Projects[0].Members[0].Company.Phone.Number"))
	//Output:
	// {
	// 	"Name": "",
	// 	"Score": 0,
	// 	"Gender": 0,
	// 	"Company": null,
	// 	"Departments": null,
	// 	"Projects": [
	// 		{
	// 			"Id": "",
	// 			"Name": "",
	// 			"Members": [
	// 				{
	// 					"Name": "",
	// 					"Score": 0,
	// 					"Gender": 0,
	// 					"Company": {
	// 						"Name": "",
	// 						"Phone": {
	// 							"Number": "911"
	// 						}
	// 					},
	// 					"Departments": null,
	// 					"Projects": null,
	// 					"Phones": null,
	// 					"Languages": null
	// 				}
	// 			]
	// 		}
	// 	],
	// 	"Phones": null,
	// 	"Languages": null
	// }
	// 911

A new way to append to an array

	var p *Person
	for i := 1; i < 6; i++ {
	    var d *Department
	    Set(&d, "Id", i)
	    Set(&d, "Name", fmt.Sprintf("Department of Energy %d", i))
	    Set(&p, "Departments[]", d)
	}
	printJsonV(p)
	//Output:
	// {
	// 	"Name": "",
	// 	"Score": 0,
	// 	"Gender": 0,
	// 	"Company": null,
	// 	"Departments": [
	// 		{
	// 			"Id": 1,
	// 			"Name": "Department of Energy 1"
	// 		},
	// 		{
	// 			"Id": 2,
	// 			"Name": "Department of Energy 2"
	// 		},
	// 		{
	// 			"Id": 3,
	// 			"Name": "Department of Energy 3"
	// 		},
	// 		{
	// 			"Id": 4,
	// 			"Name": "Department of Energy 4"
	// 		},
	// 		{
	// 			"Id": 5,
	// 			"Name": "Department of Energy 5"
	// 		}
	// 	],
	// 	"Projects": null,
	// 	"Phones": null,
	// 	"Languages": null
	// }

You could also set []byte data to string property, and vice versa. And set string value to int, float

	type Obj struct {
	    ByteProperty     []byte
	    StringProperty   string
	    IntValue         int
	    FloatValue       float64
	    IntValueForBytes int
	}
	var o *Obj
	Set(&o, "ByteProperty", "hello")
	Set(&o, "StringProperty", []byte{0x46, 0x65, 0x6c, 0x69, 0x78})
	Set(&o, "IntValue", "22")
	Set(&o, "IntValueForBytes", []byte{0x32, 0x32})
	Set(&o, "FloatValue", "22.88")
	fmt.Println(string(o.ByteProperty))
	fmt.Println(o.StringProperty)
	fmt.Println(o.IntValue)
	fmt.Println(o.FloatValue)
	fmt.Println(o.IntValueForBytes)
	//Output:
	//hello
	//Felix
	//22
	//22.88
	//22

If you set a property that don't exists, it gives you an error.

	var p *Person
	err := Set(&p, "Whatever.Not.Exists", "911")
	
	fmt.Println(err)
	//Output:
	// no such field.

Get Type of a deep nested object

	type Variant struct {
	    Name string
	}
	type Product struct {
	    Variants []*Variant
	    ByCode   map[string]*Variant
	}
	type Obj struct {
	    MainProduct *Product
	}
	
	var o *Obj
	
	fmt.Println(GetType(o, "MainProduct.Variants[0].Name"))
	fmt.Println(GetType(o, "MainProduct.Variants[0]"))
	fmt.Println(GetType(o, "MainProduct.Variants"))
	fmt.Println(GetType(o, "MainProduct"))
	fmt.Println(GetType(o, "MainProduct.ByCode.abc"))
	fmt.Println(GetType(o, "MainProduct.ByCode"))
	fmt.Println(GetType(o, "x123.ByCode"))
	fmt.Println(GetType(o, "MainProduct.ByCode.abc.NotExist"))
	//Output:
	//string
	//*reflectutils_test.Variant
	//[]*reflectutils_test.Variant
	//*reflectutils_test.Product
	//*reflectutils_test.Variant
	//map[string]*reflectutils_test.Variant
	//<nil>
	//<nil>