Address comments; Also internally start using JSONBase instead of reflect.Value of JSONBase.

This commit is contained in:
Daniel Smith 2014-06-23 09:54:01 -07:00
parent 41534c1cc5
commit ee75bb8dbe
2 changed files with 24 additions and 35 deletions

View File

@ -28,9 +28,12 @@ var knownTypes = map[string]reflect.Type{}
func init() { func init() {
AddKnownTypes( AddKnownTypes(
PodList{}, Pod{}, PodList{},
ReplicationControllerList{}, ReplicationController{}, Pod{},
ServiceList{}, Service{}, ReplicationControllerList{},
ReplicationController{},
ServiceList{},
Service{},
Status{}, Status{},
) )
} }
@ -52,25 +55,13 @@ func AddKnownTypes(types ...interface{}) {
// format. // format.
func Encode(obj interface{}) (data []byte, err error) { func Encode(obj interface{}) (data []byte, err error) {
obj = checkPtr(obj) obj = checkPtr(obj)
fieldToReset, err := prepareEncode(obj) jsonBase, err := prepareEncode(obj)
if err != nil {
return nil, err
}
data, err = json.Marshal(obj)
fieldToReset.SetString("")
return
}
// Just like Encode, but produces indented output.
func EncodeIndent(obj interface{}) (data []byte, err error) {
obj = checkPtr(obj)
fieldToReset, err := prepareEncode(obj)
if err != nil { if err != nil {
return nil, err return nil, err
} }
data, err = json.MarshalIndent(obj, "", " ") data, err = json.MarshalIndent(obj, "", " ")
fieldToReset.SetString("") jsonBase.Kind = ""
return return data, err
} }
func checkPtr(obj interface{}) interface{} { func checkPtr(obj interface{}) interface{} {
@ -83,35 +74,34 @@ func checkPtr(obj interface{}) interface{} {
return v2.Interface() return v2.Interface()
} }
func prepareEncode(obj interface{}) (reflect.Value, error) { func prepareEncode(obj interface{}) (*JSONBase, error) {
name, jsonBase, err := nameAndJSONBase(obj) name, jsonBase, err := nameAndJSONBase(obj)
if err != nil { if err != nil {
return reflect.Value{}, err return nil, err
} }
if _, contains := knownTypes[name]; !contains { if _, contains := knownTypes[name]; !contains {
return reflect.Value{}, fmt.Errorf("struct %v won't be unmarshalable because it's not in knownTypes", name) return nil, fmt.Errorf("struct %v won't be unmarshalable because it's not in knownTypes", name)
} }
kind := jsonBase.FieldByName("Kind") jsonBase.Kind = name
kind.SetString(name) return jsonBase, nil
return kind, nil
} }
// Returns the name of the type (sans pointer), and its kind field. Takes pointer-to-struct.. // Returns the name of the type (sans pointer), and its kind field. Takes pointer-to-struct..
func nameAndJSONBase(obj interface{}) (string, reflect.Value, error) { func nameAndJSONBase(obj interface{}) (string, *JSONBase, error) {
v := reflect.ValueOf(obj) v := reflect.ValueOf(obj)
if v.Kind() != reflect.Ptr { if v.Kind() != reflect.Ptr {
return "", reflect.Value{}, fmt.Errorf("expected pointer, but got %v", v.Type().Name()) return "", nil, fmt.Errorf("expected pointer, but got %v", v.Type().Name())
} }
v = v.Elem() v = v.Elem()
name := v.Type().Name() name := v.Type().Name()
if v.Kind() != reflect.Struct { if v.Kind() != reflect.Struct {
return "", reflect.Value{}, fmt.Errorf("expected struct, but got %v", name) return "", nil, fmt.Errorf("expected struct, but got %v", name)
} }
jsonBase := v.FieldByName("JSONBase") jsonBase := v.FieldByName("JSONBase")
if !jsonBase.IsValid() { if !jsonBase.IsValid() {
return "", reflect.Value{}, fmt.Errorf("struct %v lacks embedded JSON type", name) return "", nil, fmt.Errorf("struct %v lacks embedded JSON type", name)
} }
return name, jsonBase, nil return name, jsonBase.Addr().Interface().(*JSONBase), nil
} }
// Decode converts a JSON string back into a pointer to an api object. Deduces the type // Decode converts a JSON string back into a pointer to an api object. Deduces the type
@ -139,7 +129,7 @@ func Decode(data []byte) (interface{}, error) {
return nil, err return nil, err
} }
// Don't leave these set. Track type with go's type. // Don't leave these set. Track type with go's type.
jsonBase.FieldByName("Kind").SetString("") jsonBase.Kind = ""
return obj, nil return obj, nil
} }
@ -155,11 +145,10 @@ func DecodeInto(data []byte, obj interface{}) error {
if err != nil { if err != nil {
return err return err
} }
foundName := jsonBase.FieldByName("Kind").Interface().(string) if jsonBase.Kind != "" && jsonBase.Kind != name {
if foundName != "" && foundName != name { return fmt.Errorf("data had kind %v, but passed object was of type %v", jsonBase.Kind, name)
return fmt.Errorf("data had kind %v, but passed object was of type %v", foundName, name)
} }
// Don't leave these set. Track type with go's type. // Don't leave these set. Track type with go's type.
jsonBase.FieldByName("Kind").SetString("") jsonBase.Kind = ""
return nil return nil
} }

View File

@ -125,7 +125,7 @@ func (server *ApiServer) notFound(req *http.Request, w http.ResponseWriter) {
func (server *ApiServer) write(statusCode int, object interface{}, w http.ResponseWriter) { func (server *ApiServer) write(statusCode int, object interface{}, w http.ResponseWriter) {
w.WriteHeader(statusCode) w.WriteHeader(statusCode)
output, err := api.EncodeIndent(object) output, err := api.Encode(object)
if err != nil { if err != nil {
server.error(err, w) server.error(err, w)
return return