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  }