reflectcache.go 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464
  1. /*
  2. Copyright 2020 The Kubernetes Authors.
  3. Licensed under the Apache License, Version 2.0 (the "License");
  4. you may not use this file except in compliance with the License.
  5. You may obtain a copy of the License at
  6. http://www.apache.org/licenses/LICENSE-2.0
  7. Unless required by applicable law or agreed to in writing, software
  8. distributed under the License is distributed on an "AS IS" BASIS,
  9. WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  10. See the License for the specific language governing permissions and
  11. limitations under the License.
  12. */
  13. package value
  14. import (
  15. "bytes"
  16. "encoding/json"
  17. "fmt"
  18. "reflect"
  19. "sort"
  20. "sync"
  21. "sync/atomic"
  22. )
  23. // UnstructuredConverter defines how a type can be converted directly to unstructured.
  24. // Types that implement json.Marshaler may also optionally implement this interface to provide a more
  25. // direct and more efficient conversion. All types that choose to implement this interface must still
  26. // implement this same conversion via json.Marshaler.
  27. type UnstructuredConverter interface {
  28. json.Marshaler // require that json.Marshaler is implemented
  29. // ToUnstructured returns the unstructured representation.
  30. ToUnstructured() interface{}
  31. }
  32. // TypeReflectCacheEntry keeps data gathered using reflection about how a type is converted to/from unstructured.
  33. type TypeReflectCacheEntry struct {
  34. isJsonMarshaler bool
  35. ptrIsJsonMarshaler bool
  36. isJsonUnmarshaler bool
  37. ptrIsJsonUnmarshaler bool
  38. isStringConvertable bool
  39. ptrIsStringConvertable bool
  40. structFields map[string]*FieldCacheEntry
  41. orderedStructFields []*FieldCacheEntry
  42. }
  43. // FieldCacheEntry keeps data gathered using reflection about how the field of a struct is converted to/from
  44. // unstructured.
  45. type FieldCacheEntry struct {
  46. // JsonName returns the name of the field according to the json tags on the struct field.
  47. JsonName string
  48. // isOmitEmpty is true if the field has the json 'omitempty' tag.
  49. isOmitEmpty bool
  50. // fieldPath is a list of field indices (see FieldByIndex) to lookup the value of
  51. // a field in a reflect.Value struct. The field indices in the list form a path used
  52. // to traverse through intermediary 'inline' fields.
  53. fieldPath [][]int
  54. fieldType reflect.Type
  55. TypeEntry *TypeReflectCacheEntry
  56. }
  57. func (f *FieldCacheEntry) CanOmit(fieldVal reflect.Value) bool {
  58. return f.isOmitEmpty && (safeIsNil(fieldVal) || isZero(fieldVal))
  59. }
  60. // GetUsing returns the field identified by this FieldCacheEntry from the provided struct.
  61. func (f *FieldCacheEntry) GetFrom(structVal reflect.Value) reflect.Value {
  62. // field might be nested within 'inline' structs
  63. for _, elem := range f.fieldPath {
  64. structVal = structVal.FieldByIndex(elem)
  65. }
  66. return structVal
  67. }
  68. var marshalerType = reflect.TypeOf(new(json.Marshaler)).Elem()
  69. var unmarshalerType = reflect.TypeOf(new(json.Unmarshaler)).Elem()
  70. var unstructuredConvertableType = reflect.TypeOf(new(UnstructuredConverter)).Elem()
  71. var defaultReflectCache = newReflectCache()
  72. // TypeReflectEntryOf returns the TypeReflectCacheEntry of the provided reflect.Type.
  73. func TypeReflectEntryOf(t reflect.Type) *TypeReflectCacheEntry {
  74. cm := defaultReflectCache.get()
  75. if record, ok := cm[t]; ok {
  76. return record
  77. }
  78. updates := reflectCacheMap{}
  79. result := typeReflectEntryOf(cm, t, updates)
  80. if len(updates) > 0 {
  81. defaultReflectCache.update(updates)
  82. }
  83. return result
  84. }
  85. // TypeReflectEntryOf returns all updates needed to add provided reflect.Type, and the types its fields transitively
  86. // depend on, to the cache.
  87. func typeReflectEntryOf(cm reflectCacheMap, t reflect.Type, updates reflectCacheMap) *TypeReflectCacheEntry {
  88. if record, ok := cm[t]; ok {
  89. return record
  90. }
  91. if record, ok := updates[t]; ok {
  92. return record
  93. }
  94. typeEntry := &TypeReflectCacheEntry{
  95. isJsonMarshaler: t.Implements(marshalerType),
  96. ptrIsJsonMarshaler: reflect.PtrTo(t).Implements(marshalerType),
  97. isJsonUnmarshaler: reflect.PtrTo(t).Implements(unmarshalerType),
  98. isStringConvertable: t.Implements(unstructuredConvertableType),
  99. ptrIsStringConvertable: reflect.PtrTo(t).Implements(unstructuredConvertableType),
  100. }
  101. if t.Kind() == reflect.Struct {
  102. fieldEntries := map[string]*FieldCacheEntry{}
  103. buildStructCacheEntry(t, fieldEntries, nil)
  104. typeEntry.structFields = fieldEntries
  105. sortedByJsonName := make([]*FieldCacheEntry, len(fieldEntries))
  106. i := 0
  107. for _, entry := range fieldEntries {
  108. sortedByJsonName[i] = entry
  109. i++
  110. }
  111. sort.Slice(sortedByJsonName, func(i, j int) bool {
  112. return sortedByJsonName[i].JsonName < sortedByJsonName[j].JsonName
  113. })
  114. typeEntry.orderedStructFields = sortedByJsonName
  115. }
  116. // cyclic type references are allowed, so we must add the typeEntry to the updates map before resolving
  117. // the field.typeEntry references, or creating them if they are not already in the cache
  118. updates[t] = typeEntry
  119. for _, field := range typeEntry.structFields {
  120. if field.TypeEntry == nil {
  121. field.TypeEntry = typeReflectEntryOf(cm, field.fieldType, updates)
  122. }
  123. }
  124. return typeEntry
  125. }
  126. func buildStructCacheEntry(t reflect.Type, infos map[string]*FieldCacheEntry, fieldPath [][]int) {
  127. for i := 0; i < t.NumField(); i++ {
  128. field := t.Field(i)
  129. jsonName, omit, isInline, isOmitempty := lookupJsonTags(field)
  130. if omit {
  131. continue
  132. }
  133. if isInline {
  134. buildStructCacheEntry(field.Type, infos, append(fieldPath, field.Index))
  135. continue
  136. }
  137. info := &FieldCacheEntry{JsonName: jsonName, isOmitEmpty: isOmitempty, fieldPath: append(fieldPath, field.Index), fieldType: field.Type}
  138. infos[jsonName] = info
  139. }
  140. }
  141. // Fields returns a map of JSON field name to FieldCacheEntry for structs, or nil for non-structs.
  142. func (e TypeReflectCacheEntry) Fields() map[string]*FieldCacheEntry {
  143. return e.structFields
  144. }
  145. // Fields returns a map of JSON field name to FieldCacheEntry for structs, or nil for non-structs.
  146. func (e TypeReflectCacheEntry) OrderedFields() []*FieldCacheEntry {
  147. return e.orderedStructFields
  148. }
  149. // CanConvertToUnstructured returns true if this TypeReflectCacheEntry can convert values of its type to unstructured.
  150. func (e TypeReflectCacheEntry) CanConvertToUnstructured() bool {
  151. return e.isJsonMarshaler || e.ptrIsJsonMarshaler || e.isStringConvertable || e.ptrIsStringConvertable
  152. }
  153. // ToUnstructured converts the provided value to unstructured and returns it.
  154. func (e TypeReflectCacheEntry) ToUnstructured(sv reflect.Value) (interface{}, error) {
  155. // This is based on https://github.com/kubernetes/kubernetes/blob/82c9e5c814eb7acc6cc0a090c057294d0667ad66/staging/src/k8s.io/apimachinery/pkg/runtime/converter.go#L505
  156. // and is intended to replace it.
  157. // Check if the object has a custom string converter and use it if available, since it is much more efficient
  158. // than round tripping through json.
  159. if converter, ok := e.getUnstructuredConverter(sv); ok {
  160. return converter.ToUnstructured(), nil
  161. }
  162. // Check if the object has a custom JSON marshaller/unmarshaller.
  163. if marshaler, ok := e.getJsonMarshaler(sv); ok {
  164. if sv.Kind() == reflect.Ptr && sv.IsNil() {
  165. // We're done - we don't need to store anything.
  166. return nil, nil
  167. }
  168. data, err := marshaler.MarshalJSON()
  169. if err != nil {
  170. return nil, err
  171. }
  172. switch {
  173. case len(data) == 0:
  174. return nil, fmt.Errorf("error decoding from json: empty value")
  175. case bytes.Equal(data, nullBytes):
  176. // We're done - we don't need to store anything.
  177. return nil, nil
  178. case bytes.Equal(data, trueBytes):
  179. return true, nil
  180. case bytes.Equal(data, falseBytes):
  181. return false, nil
  182. case data[0] == '"':
  183. var result string
  184. err := unmarshal(data, &result)
  185. if err != nil {
  186. return nil, fmt.Errorf("error decoding string from json: %v", err)
  187. }
  188. return result, nil
  189. case data[0] == '{':
  190. result := make(map[string]interface{})
  191. err := unmarshal(data, &result)
  192. if err != nil {
  193. return nil, fmt.Errorf("error decoding object from json: %v", err)
  194. }
  195. return result, nil
  196. case data[0] == '[':
  197. result := make([]interface{}, 0)
  198. err := unmarshal(data, &result)
  199. if err != nil {
  200. return nil, fmt.Errorf("error decoding array from json: %v", err)
  201. }
  202. return result, nil
  203. default:
  204. var (
  205. resultInt int64
  206. resultFloat float64
  207. err error
  208. )
  209. if err = unmarshal(data, &resultInt); err == nil {
  210. return resultInt, nil
  211. } else if err = unmarshal(data, &resultFloat); err == nil {
  212. return resultFloat, nil
  213. } else {
  214. return nil, fmt.Errorf("error decoding number from json: %v", err)
  215. }
  216. }
  217. }
  218. return nil, fmt.Errorf("provided type cannot be converted: %v", sv.Type())
  219. }
  220. // CanConvertFromUnstructured returns true if this TypeReflectCacheEntry can convert objects of the type from unstructured.
  221. func (e TypeReflectCacheEntry) CanConvertFromUnstructured() bool {
  222. return e.isJsonUnmarshaler
  223. }
  224. // FromUnstructured converts the provided source value from unstructured into the provided destination value.
  225. func (e TypeReflectCacheEntry) FromUnstructured(sv, dv reflect.Value) error {
  226. // TODO: this could be made much more efficient using direct conversions like
  227. // UnstructuredConverter.ToUnstructured provides.
  228. st := dv.Type()
  229. data, err := json.Marshal(sv.Interface())
  230. if err != nil {
  231. return fmt.Errorf("error encoding %s to json: %v", st.String(), err)
  232. }
  233. if unmarshaler, ok := e.getJsonUnmarshaler(dv); ok {
  234. return unmarshaler.UnmarshalJSON(data)
  235. }
  236. return fmt.Errorf("unable to unmarshal %v into %v", sv.Type(), dv.Type())
  237. }
  238. var (
  239. nullBytes = []byte("null")
  240. trueBytes = []byte("true")
  241. falseBytes = []byte("false")
  242. )
  243. func (e TypeReflectCacheEntry) getJsonMarshaler(v reflect.Value) (json.Marshaler, bool) {
  244. if e.isJsonMarshaler {
  245. return v.Interface().(json.Marshaler), true
  246. }
  247. if e.ptrIsJsonMarshaler {
  248. // Check pointer receivers if v is not a pointer
  249. if v.Kind() != reflect.Ptr && v.CanAddr() {
  250. v = v.Addr()
  251. return v.Interface().(json.Marshaler), true
  252. }
  253. }
  254. return nil, false
  255. }
  256. func (e TypeReflectCacheEntry) getJsonUnmarshaler(v reflect.Value) (json.Unmarshaler, bool) {
  257. if !e.isJsonUnmarshaler {
  258. return nil, false
  259. }
  260. return v.Addr().Interface().(json.Unmarshaler), true
  261. }
  262. func (e TypeReflectCacheEntry) getUnstructuredConverter(v reflect.Value) (UnstructuredConverter, bool) {
  263. if e.isStringConvertable {
  264. return v.Interface().(UnstructuredConverter), true
  265. }
  266. if e.ptrIsStringConvertable {
  267. // Check pointer receivers if v is not a pointer
  268. if v.CanAddr() {
  269. v = v.Addr()
  270. return v.Interface().(UnstructuredConverter), true
  271. }
  272. }
  273. return nil, false
  274. }
  275. type typeReflectCache struct {
  276. // use an atomic and copy-on-write since there are a fixed (typically very small) number of structs compiled into any
  277. // go program using this cache
  278. value atomic.Value
  279. // mu is held by writers when performing load/modify/store operations on the cache, readers do not need to hold a
  280. // read-lock since the atomic value is always read-only
  281. mu sync.Mutex
  282. }
  283. func newReflectCache() *typeReflectCache {
  284. cache := &typeReflectCache{}
  285. cache.value.Store(make(reflectCacheMap))
  286. return cache
  287. }
  288. type reflectCacheMap map[reflect.Type]*TypeReflectCacheEntry
  289. // get returns the reflectCacheMap.
  290. func (c *typeReflectCache) get() reflectCacheMap {
  291. return c.value.Load().(reflectCacheMap)
  292. }
  293. // update merges the provided updates into the cache.
  294. func (c *typeReflectCache) update(updates reflectCacheMap) {
  295. c.mu.Lock()
  296. defer c.mu.Unlock()
  297. currentCacheMap := c.value.Load().(reflectCacheMap)
  298. hasNewEntries := false
  299. for t := range updates {
  300. if _, ok := currentCacheMap[t]; !ok {
  301. hasNewEntries = true
  302. break
  303. }
  304. }
  305. if !hasNewEntries {
  306. // Bail if the updates have been set while waiting for lock acquisition.
  307. // This is safe since setting entries is idempotent.
  308. return
  309. }
  310. newCacheMap := make(reflectCacheMap, len(currentCacheMap)+len(updates))
  311. for k, v := range currentCacheMap {
  312. newCacheMap[k] = v
  313. }
  314. for t, update := range updates {
  315. newCacheMap[t] = update
  316. }
  317. c.value.Store(newCacheMap)
  318. }
  319. // Below json Unmarshal is fromk8s.io/apimachinery/pkg/util/json
  320. // to handle number conversions as expected by Kubernetes
  321. // limit recursive depth to prevent stack overflow errors
  322. const maxDepth = 10000
  323. // unmarshal unmarshals the given data
  324. // If v is a *map[string]interface{}, numbers are converted to int64 or float64
  325. func unmarshal(data []byte, v interface{}) error {
  326. switch v := v.(type) {
  327. case *map[string]interface{}:
  328. // Build a decoder from the given data
  329. decoder := json.NewDecoder(bytes.NewBuffer(data))
  330. // Preserve numbers, rather than casting to float64 automatically
  331. decoder.UseNumber()
  332. // Run the decode
  333. if err := decoder.Decode(v); err != nil {
  334. return err
  335. }
  336. // If the decode succeeds, post-process the map to convert json.Number objects to int64 or float64
  337. return convertMapNumbers(*v, 0)
  338. case *[]interface{}:
  339. // Build a decoder from the given data
  340. decoder := json.NewDecoder(bytes.NewBuffer(data))
  341. // Preserve numbers, rather than casting to float64 automatically
  342. decoder.UseNumber()
  343. // Run the decode
  344. if err := decoder.Decode(v); err != nil {
  345. return err
  346. }
  347. // If the decode succeeds, post-process the map to convert json.Number objects to int64 or float64
  348. return convertSliceNumbers(*v, 0)
  349. default:
  350. return json.Unmarshal(data, v)
  351. }
  352. }
  353. // convertMapNumbers traverses the map, converting any json.Number values to int64 or float64.
  354. // values which are map[string]interface{} or []interface{} are recursively visited
  355. func convertMapNumbers(m map[string]interface{}, depth int) error {
  356. if depth > maxDepth {
  357. return fmt.Errorf("exceeded max depth of %d", maxDepth)
  358. }
  359. var err error
  360. for k, v := range m {
  361. switch v := v.(type) {
  362. case json.Number:
  363. m[k], err = convertNumber(v)
  364. case map[string]interface{}:
  365. err = convertMapNumbers(v, depth+1)
  366. case []interface{}:
  367. err = convertSliceNumbers(v, depth+1)
  368. }
  369. if err != nil {
  370. return err
  371. }
  372. }
  373. return nil
  374. }
  375. // convertSliceNumbers traverses the slice, converting any json.Number values to int64 or float64.
  376. // values which are map[string]interface{} or []interface{} are recursively visited
  377. func convertSliceNumbers(s []interface{}, depth int) error {
  378. if depth > maxDepth {
  379. return fmt.Errorf("exceeded max depth of %d", maxDepth)
  380. }
  381. var err error
  382. for i, v := range s {
  383. switch v := v.(type) {
  384. case json.Number:
  385. s[i], err = convertNumber(v)
  386. case map[string]interface{}:
  387. err = convertMapNumbers(v, depth+1)
  388. case []interface{}:
  389. err = convertSliceNumbers(v, depth+1)
  390. }
  391. if err != nil {
  392. return err
  393. }
  394. }
  395. return nil
  396. }
  397. // convertNumber converts a json.Number to an int64 or float64, or returns an error
  398. func convertNumber(n json.Number) (interface{}, error) {
  399. // Attempt to convert to an int64 first
  400. if i, err := n.Int64(); err == nil {
  401. return i, nil
  402. }
  403. // Return a float64 (default json.Decode() behavior)
  404. // An overflow will return an error
  405. return n.Float64()
  406. }