Created
February 2, 2017 15:03
-
-
Save owulveryck/8e816bbf931190d5a9d10509fd6937b1 to your computer and use it in GitHub Desktop.
Golang / Reflection
This file contains hidden or 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 item | |
import ( | |
"errors" | |
"reflect" | |
) | |
// Marshal takes an interface and returns an Item compatible with tidedot | |
func Marshal(o interface{}) map[string]interface{} { | |
oType := reflect.TypeOf(o) | |
// Get the numeber of fields in the interface | |
numField := oType.NumField() | |
result := make(map[string]interface{}, numField) | |
for i := 0; i < numField; i++ { | |
f := oType.Field(i) | |
// No need to save a private field as we won't be able to restore it | |
if f.PkgPath == "" { | |
result[f.Name] = reflect.ValueOf(o).Field(i).Interface() | |
} | |
} | |
return result | |
} | |
// Unmarshal parses i and sets it if possible into o | |
// returns an error if not possible or if interface is not a struct | |
func Unmarshal(i map[string]interface{}, o interface{}) error { | |
oType := reflect.TypeOf(o) | |
if oType.Kind() != reflect.Ptr { | |
return errors.New("Expected pointer") | |
} | |
//temp := reflect.New(oType) | |
oVal := reflect.ValueOf(o).Elem() | |
if oVal.Kind() != reflect.Struct { | |
return errors.New("Interface is " + oType.Kind().String() + ", not struct") | |
} | |
for k, v := range i { | |
f := oVal.FieldByName(k) | |
if f.IsValid() { | |
// A Value can be changed only if it is | |
// addressable and was not obtained by | |
// the use of unexported struct fields. | |
if f.CanSet() { | |
if f.Kind() == reflect.ValueOf(v).Kind() { | |
f.Set(reflect.ValueOf(v)) | |
} else { | |
return errors.New("Cannot set " + reflect.ValueOf(v).Kind().String() + " into " + f.Kind().String()) | |
} | |
} else { | |
return errors.New("Cannot set field " + k) | |
} | |
} else { | |
return errors.New("Field \"" + k + "\" is not valid") | |
} | |
} | |
return nil | |
} |
This file contains hidden or 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 item | |
import ( | |
"testing" | |
) | |
type testStruct struct { | |
ID string | |
Field1 int64 | |
Field3 float64 | |
private string | |
Struct subStruct | |
} | |
type subStruct struct { | |
ID string | |
} | |
func TestUnmarshal(t *testing.T) { | |
var test testStruct | |
vals := map[string]interface{}{ | |
"ID": "foo", | |
"Field1": int64(1), | |
"Field3": float64(2.0), | |
"Struct": subStruct{"subid"}, | |
} | |
err := Unmarshal(vals, &test) | |
if err != nil { | |
t.Fatal(err) | |
} | |
t.Log(test) | |
vals = map[string]interface{}{ | |
"id": "foo", | |
"Field1": int64(1), | |
"Field3": float64(2.0), | |
} | |
err = Unmarshal(vals, &test) | |
if err != nil { | |
t.Log(err) | |
} else { | |
t.Fail() | |
} | |
} | |
func TestMarshal(t *testing.T) { | |
test := testStruct{ | |
ID: "foo", | |
Field1: int64(1), | |
Field3: float64(2.1), | |
Struct: subStruct{"subid"}, | |
} | |
t.Log(test) | |
it := Marshal(test) | |
t.Log(it) | |
err := Unmarshal(it, &test) | |
if err != nil { | |
t.Fatal(err) | |
} | |
t.Log(test) | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment