github.com/aclisp/heapster@v0.19.2-0.20160613100040-51756f899a96/Godeps/_workspace/src/k8s.io/kubernetes/pkg/util/json/json.go (about) 1 /* 2 Copyright 2015 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 json 18 19 import ( 20 "bytes" 21 "encoding/json" 22 "io" 23 ) 24 25 // NewEncoder delegates to json.NewEncoder 26 // It is only here so this package can be a drop-in for common encoding/json uses 27 func NewEncoder(w io.Writer) *json.Encoder { 28 return json.NewEncoder(w) 29 } 30 31 // Marshal delegates to json.Marshal 32 // It is only here so this package can be a drop-in for common encoding/json uses 33 func Marshal(v interface{}) ([]byte, error) { 34 return json.Marshal(v) 35 } 36 37 // Unmarshal unmarshals the given data 38 // If v is a *map[string]interface{}, numbers are converted to int64 or float64 39 func Unmarshal(data []byte, v interface{}) error { 40 switch v := v.(type) { 41 case *map[string]interface{}: 42 // Build a decoder from the given data 43 decoder := json.NewDecoder(bytes.NewBuffer(data)) 44 // Preserve numbers, rather than casting to float64 automatically 45 decoder.UseNumber() 46 // Run the decode 47 if err := decoder.Decode(v); err != nil { 48 return err 49 } 50 // If the decode succeeds, post-process the map to convert json.Number objects to int64 or float64 51 return convertMapNumbers(*v) 52 53 default: 54 return json.Unmarshal(data, v) 55 } 56 } 57 58 // convertMapNumbers traverses the map, converting any json.Number values to int64 or float64. 59 // values which are map[string]interface{} or []interface{} are recursively visited 60 func convertMapNumbers(m map[string]interface{}) error { 61 var err error 62 for k, v := range m { 63 switch v := v.(type) { 64 case json.Number: 65 m[k], err = convertNumber(v) 66 case map[string]interface{}: 67 err = convertMapNumbers(v) 68 case []interface{}: 69 err = convertSliceNumbers(v) 70 } 71 if err != nil { 72 return err 73 } 74 } 75 return nil 76 } 77 78 // convertSliceNumbers traverses the slice, converting any json.Number values to int64 or float64. 79 // values which are map[string]interface{} or []interface{} are recursively visited 80 func convertSliceNumbers(s []interface{}) error { 81 var err error 82 for i, v := range s { 83 switch v := v.(type) { 84 case json.Number: 85 s[i], err = convertNumber(v) 86 case map[string]interface{}: 87 err = convertMapNumbers(v) 88 case []interface{}: 89 err = convertSliceNumbers(v) 90 } 91 if err != nil { 92 return err 93 } 94 } 95 return nil 96 } 97 98 // convertNumber converts a json.Number to an int64 or float64, or returns an error 99 func convertNumber(n json.Number) (interface{}, error) { 100 // Attempt to convert to an int64 first 101 if i, err := n.Int64(); err == nil { 102 return i, nil 103 } 104 // Return a float64 (default json.Decode() behavior) 105 // An overflow will return an error 106 return n.Float64() 107 }