diff --git a/client.go b/client.go index eef267a2..902c2108 100644 --- a/client.go +++ b/client.go @@ -306,7 +306,10 @@ func (clnt *Client) Get(policy *BasePolicy, key *Key, binNames ...string) (*Reco func (clnt *Client) GetObject(policy *BasePolicy, key *Key, obj interface{}) error { policy = clnt.getUsablePolicy(policy) - binNames := objectMappings.getFields(reflect.ValueOf(obj).Type().Elem().Name()) + rval := reflect.ValueOf(obj) + cacheObjectTags(rval) + binNames := objectMappings.getFields(rval) + command := newReadCommand(clnt.cluster, policy, key, binNames) command.object = obj if err := command.Execute(); err != nil { diff --git a/marshal.go b/marshal.go index fbe3697b..ea3e4478 100644 --- a/marshal.go +++ b/marshal.go @@ -120,18 +120,16 @@ func structToMap(s reflect.Value) map[string]interface{} { binValue := valueToInterface(s.Field(i)) - if binValue != nil { - if binMap == nil { - binMap = make(map[string]interface{}, numFields) - } - - alias := fieldAlias(typeOfT.Field(i)) - if alias == "" { - continue - } + if binMap == nil { + binMap = make(map[string]interface{}, numFields) + } - binMap[alias] = binValue + alias := fieldAlias(typeOfT.Field(i)) + if alias == "" { + continue } + + binMap[alias] = binValue } return binMap @@ -156,16 +154,14 @@ func marshal(v interface{}) []*Bin { binValue := valueToInterface(s.Field(i)) - if binValue != nil { - alias := fieldAlias(typeOfT.Field(i)) - if alias == "" { - continue - } - - bins[binCount].Name = alias - bins[binCount].Value = NewValue(binValue) - binCount++ + alias := fieldAlias(typeOfT.Field(i)) + if alias == "" { + continue } + + bins[binCount].Name = alias + bins[binCount].Value = NewValue(binValue) + binCount++ } return bins[:binCount] @@ -177,27 +173,32 @@ type SyncMap struct { mutex sync.RWMutex } -func (sm *SyncMap) setMapping(objType string, mapping map[string]string, fields []string) { +func (sm *SyncMap) setMapping(obj reflect.Value, mapping map[string]string, fields []string) { + objType := obj.Type().Name() sm.mutex.Lock() sm.objectMappings[objType] = mapping + sm.objectFields[objType] = fields sm.mutex.Unlock() } -func (sm *SyncMap) mappingExists(objType string) bool { +func (sm *SyncMap) mappingExists(obj reflect.Value) bool { + objType := obj.Type().Name() sm.mutex.RLock() _, exists := sm.objectMappings[objType] sm.mutex.RUnlock() return exists } -func (sm *SyncMap) getMapping(objType string) map[string]string { +func (sm *SyncMap) getMapping(obj reflect.Value) map[string]string { + objType := obj.Type().Name() sm.mutex.RLock() mapping := sm.objectMappings[objType] sm.mutex.RUnlock() return mapping } -func (sm *SyncMap) getFields(objType string) []string { +func (sm *SyncMap) getFields(obj reflect.Value) []string { + objType := obj.Type().Name() sm.mutex.RLock() fields := sm.objectFields[objType] sm.mutex.RUnlock() @@ -207,12 +208,18 @@ func (sm *SyncMap) getFields(objType string) []string { var objectMappings = &SyncMap{objectMappings: map[string]map[string]string{}, objectFields: map[string][]string{}} func cacheObjectTags(obj reflect.Value) { - objType := obj.Type().Name() // exit if already processed - if objectMappings.mappingExists(objType) { + if objectMappings.mappingExists(obj) { return } + for obj.Kind() == reflect.Ptr { + if obj.IsNil() { + return + } + obj = reflect.Indirect(obj) + } + mapping := map[string]string{} fields := []string{} @@ -236,5 +243,5 @@ func cacheObjectTags(obj reflect.Value) { } } - objectMappings.setMapping(objType, mapping, fields) + objectMappings.setMapping(obj, mapping, fields) } diff --git a/read_command.go b/read_command.go index 16a017d0..e0b835b2 100644 --- a/read_command.go +++ b/read_command.go @@ -226,6 +226,10 @@ func (cmd *readCommand) Execute() error { } func (cmd *readCommand) setObjectField(obj reflect.Value, fieldName string, value interface{}) error { + if value == nil { + return nil + } + // find the name based on tag mapping iobj := reflect.Indirect(obj) if name, exists := cmd.objectMappings[iobj.Type().Name()][fieldName]; exists {