github.com/timstclair/heapster@v0.20.0-alpha1/Godeps/_workspace/src/k8s.io/kubernetes/pkg/conversion/queryparams/convert.go (about) 1 /* 2 Copyright 2014 The Kubernetes Authors All rights reserved. 3 4 Licensed under the Apache License, Version 2.0 (the "License"); 5 you may not use this file except in compliance with the License. 6 You may obtain a copy of the License at 7 8 http://www.apache.org/licenses/LICENSE-2.0 9 10 Unless required by applicable law or agreed to in writing, software 11 distributed under the License is distributed on an "AS IS" BASIS, 12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 See the License for the specific language governing permissions and 14 limitations under the License. 15 */ 16 17 package queryparams 18 19 import ( 20 "fmt" 21 "net/url" 22 "reflect" 23 "strings" 24 25 "k8s.io/kubernetes/pkg/runtime" 26 ) 27 28 func jsonTag(field reflect.StructField) (string, bool) { 29 structTag := field.Tag.Get("json") 30 if len(structTag) == 0 { 31 return "", false 32 } 33 parts := strings.Split(structTag, ",") 34 tag := parts[0] 35 if tag == "-" { 36 tag = "" 37 } 38 omitempty := false 39 parts = parts[1:] 40 for _, part := range parts { 41 if part == "omitempty" { 42 omitempty = true 43 break 44 } 45 } 46 return tag, omitempty 47 } 48 49 func formatValue(value interface{}) string { 50 return fmt.Sprintf("%v", value) 51 } 52 53 func isPointerKind(kind reflect.Kind) bool { 54 return kind == reflect.Ptr 55 } 56 57 func isStructKind(kind reflect.Kind) bool { 58 return kind == reflect.Struct 59 } 60 61 func isValueKind(kind reflect.Kind) bool { 62 switch kind { 63 case reflect.String, reflect.Bool, reflect.Int, reflect.Int8, reflect.Int16, 64 reflect.Int32, reflect.Int64, reflect.Uint, reflect.Uint8, 65 reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Float32, 66 reflect.Float64, reflect.Complex64, reflect.Complex128: 67 return true 68 default: 69 return false 70 } 71 } 72 73 func zeroValue(value reflect.Value) bool { 74 return reflect.DeepEqual(reflect.Zero(value.Type()).Interface(), value.Interface()) 75 } 76 77 func addParam(values url.Values, tag string, omitempty bool, value reflect.Value) { 78 if omitempty && zeroValue(value) { 79 return 80 } 81 val := "" 82 iValue := fmt.Sprintf("%v", value.Interface()) 83 84 if iValue != "<nil>" { 85 val = iValue 86 } 87 values.Add(tag, val) 88 } 89 90 func addListOfParams(values url.Values, tag string, omitempty bool, list reflect.Value) { 91 for i := 0; i < list.Len(); i++ { 92 addParam(values, tag, omitempty, list.Index(i)) 93 } 94 } 95 96 // Convert takes a versioned runtime.Object and serializes it to a url.Values object 97 // using JSON tags as parameter names. Only top-level simple values, arrays, and slices 98 // are serialized. Embedded structs, maps, etc. will not be serialized. 99 func Convert(obj runtime.Object) (url.Values, error) { 100 result := url.Values{} 101 if obj == nil { 102 return result, nil 103 } 104 var sv reflect.Value 105 switch reflect.TypeOf(obj).Kind() { 106 case reflect.Ptr, reflect.Interface: 107 sv = reflect.ValueOf(obj).Elem() 108 default: 109 return nil, fmt.Errorf("expecting a pointer or interface") 110 } 111 st := sv.Type() 112 if !isStructKind(st.Kind()) { 113 return nil, fmt.Errorf("expecting a pointer to a struct") 114 } 115 116 // Check all object fields 117 convertStruct(result, st, sv) 118 119 return result, nil 120 } 121 122 func convertStruct(result url.Values, st reflect.Type, sv reflect.Value) { 123 for i := 0; i < st.NumField(); i++ { 124 field := sv.Field(i) 125 tag, omitempty := jsonTag(st.Field(i)) 126 if len(tag) == 0 { 127 continue 128 } 129 ft := field.Type() 130 131 kind := ft.Kind() 132 if isPointerKind(kind) { 133 kind = ft.Elem().Kind() 134 if !field.IsNil() { 135 field = reflect.Indirect(field) 136 } 137 } 138 139 switch { 140 case isValueKind(kind): 141 addParam(result, tag, omitempty, field) 142 case kind == reflect.Array || kind == reflect.Slice: 143 if isValueKind(ft.Elem().Kind()) { 144 addListOfParams(result, tag, omitempty, field) 145 } 146 case isStructKind(kind) && !(zeroValue(field) && omitempty): 147 convertStruct(result, ft, field) 148 } 149 } 150 }