func getResourceField(v interface{}) (f *structs.Field, err error) { var ok bool if !structs.IsStruct(v) { err = errors.New("not a struct") } else if f, ok = structs.New(v).FieldOk("Id"); !ok { err = errors.New("no 'Id' field") } else if _, ok = f.Value().(int); !ok { err = errors.New("Id field is not an int") } return }
// Determine whether the struct's id will be omitted in json encoding. func isIdOmitted(v interface{}) (bool, error) { if structs.IsStruct(v) { if f, err := getResourceField(v); err != nil { return false, err } else if jsonTag := f.Tag("json"); jsonTag == "" { // No json tag means the id field won't be ommitted. return false, nil } else { // getResourceField() ensures this is an int. id := f.Value().(int) // Json tags are comma separated. 'omitempty' means id == 0 -> id field // not included in generated json. Also note spacing, like "id, // omitempty" is significant and prevents a tag from taking effect so no // need for trimming. // // See http://golang.org/pkg/encoding/json/#Marshal for _, field := range strings.Split(jsonTag, ",") { if field == "omitempty" && id == 0 { return true, nil } } } } else { ty := reflect.TypeOf(v) switch ty.Kind() { case reflect.Map: if _, ok := v.(map[string]interface{}); !ok { return false, errors.New("Invalid map") } else { return false, nil } case reflect.Ptr: return isIdOmitted(reflect.Indirect(reflect.ValueOf(v)).Interface()) } } // Id field exists, no 'omitempty' tag so not omitted. return false, nil }