reflectcache.go 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467
  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. // GetFrom 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 = dereference(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. e := field.Type
  135. if field.Type.Kind() == reflect.Ptr {
  136. e = field.Type.Elem()
  137. }
  138. buildStructCacheEntry(e, infos, append(fieldPath, field.Index))
  139. continue
  140. }
  141. info := &FieldCacheEntry{JsonName: jsonName, isOmitEmpty: isOmitempty, fieldPath: append(fieldPath, field.Index), fieldType: field.Type}
  142. infos[jsonName] = info
  143. }
  144. }
  145. // Fields returns a map of JSON field name to FieldCacheEntry for structs, or nil for non-structs.
  146. func (e TypeReflectCacheEntry) Fields() map[string]*FieldCacheEntry {
  147. return e.structFields
  148. }
  149. // Fields returns a map of JSON field name to FieldCacheEntry for structs, or nil for non-structs.
  150. func (e TypeReflectCacheEntry) OrderedFields() []*FieldCacheEntry {
  151. return e.orderedStructFields
  152. }
  153. // CanConvertToUnstructured returns true if this TypeReflectCacheEntry can convert values of its type to unstructured.
  154. func (e TypeReflectCacheEntry) CanConvertToUnstructured() bool {
  155. return e.isJsonMarshaler || e.ptrIsJsonMarshaler || e.isStringConvertable || e.ptrIsStringConvertable
  156. }
  157. // ToUnstructured converts the provided value to unstructured and returns it.
  158. func (e TypeReflectCacheEntry) ToUnstructured(sv reflect.Value) (interface{}, error) {
  159. // This is based on https://github.com/kubernetes/kubernetes/blob/82c9e5c814eb7acc6cc0a090c057294d0667ad66/staging/src/k8s.io/apimachinery/pkg/runtime/converter.go#L505
  160. // and is intended to replace it.
  161. // Check if the object has a custom string converter and use it if available, since it is much more efficient
  162. // than round tripping through json.
  163. if converter, ok := e.getUnstructuredConverter(sv); ok {
  164. return converter.ToUnstructured(), nil
  165. }
  166. // Check if the object has a custom JSON marshaller/unmarshaller.
  167. if marshaler, ok := e.getJsonMarshaler(sv); ok {
  168. if sv.Kind() == reflect.Ptr && sv.IsNil() {
  169. // We're done - we don't need to store anything.
  170. return nil, nil
  171. }
  172. data, err := marshaler.MarshalJSON()
  173. if err != nil {
  174. return nil, err
  175. }
  176. switch {
  177. case len(data) == 0:
  178. return nil, fmt.Errorf("error decoding from json: empty value")
  179. case bytes.Equal(data, nullBytes):
  180. // We're done - we don't need to store anything.
  181. return nil, nil
  182. case bytes.Equal(data, trueBytes):
  183. return true, nil
  184. case bytes.Equal(data, falseBytes):
  185. return false, nil
  186. case data[0] == '"':
  187. var result string
  188. err := unmarshal(data, &result)
  189. if err != nil {
  190. return nil, fmt.Errorf("error decoding string from json: %v", err)
  191. }
  192. return result, nil
  193. case data[0] == '{':
  194. result := make(map[string]interface{})
  195. err := unmarshal(data, &result)
  196. if err != nil {
  197. return nil, fmt.Errorf("error decoding object from json: %v", err)
  198. }
  199. return result, nil
  200. case data[0] == '[':
  201. result := make([]interface{}, 0)
  202. err := unmarshal(data, &result)
  203. if err != nil {
  204. return nil, fmt.Errorf("error decoding array from json: %v", err)
  205. }
  206. return result, nil
  207. default:
  208. var (
  209. resultInt int64
  210. resultFloat float64
  211. err error
  212. )
  213. if err = unmarshal(data, &resultInt); err == nil {
  214. return resultInt, nil
  215. } else if err = unmarshal(data, &resultFloat); err == nil {
  216. return resultFloat, nil
  217. } else {
  218. return nil, fmt.Errorf("error decoding number from json: %v", err)
  219. }
  220. }
  221. }
  222. return nil, fmt.Errorf("provided type cannot be converted: %v", sv.Type())
  223. }
  224. // CanConvertFromUnstructured returns true if this TypeReflectCacheEntry can convert objects of the type from unstructured.
  225. func (e TypeReflectCacheEntry) CanConvertFromUnstructured() bool {
  226. return e.isJsonUnmarshaler
  227. }
  228. // FromUnstructured converts the provided source value from unstructured into the provided destination value.
  229. func (e TypeReflectCacheEntry) FromUnstructured(sv, dv reflect.Value) error {
  230. // TODO: this could be made much more efficient using direct conversions like
  231. // UnstructuredConverter.ToUnstructured provides.
  232. st := dv.Type()
  233. data, err := json.Marshal(sv.Interface())
  234. if err != nil {
  235. return fmt.Errorf("error encoding %s to json: %v", st.String(), err)
  236. }
  237. if unmarshaler, ok := e.getJsonUnmarshaler(dv); ok {
  238. return unmarshaler.UnmarshalJSON(data)
  239. }
  240. return fmt.Errorf("unable to unmarshal %v into %v", sv.Type(), dv.Type())
  241. }
  242. var (
  243. nullBytes = []byte("null")
  244. trueBytes = []byte("true")
  245. falseBytes = []byte("false")
  246. )
  247. func (e TypeReflectCacheEntry) getJsonMarshaler(v reflect.Value) (json.Marshaler, bool) {
  248. if e.isJsonMarshaler {
  249. return v.Interface().(json.Marshaler), true
  250. }
  251. if e.ptrIsJsonMarshaler {
  252. // Check pointer receivers if v is not a pointer
  253. if v.Kind() != reflect.Ptr && v.CanAddr() {
  254. v = v.Addr()
  255. return v.Interface().(json.Marshaler), true
  256. }
  257. }
  258. return nil, false
  259. }
  260. func (e TypeReflectCacheEntry) getJsonUnmarshaler(v reflect.Value) (json.Unmarshaler, bool) {
  261. if !e.isJsonUnmarshaler {
  262. return nil, false
  263. }
  264. return v.Addr().Interface().(json.Unmarshaler), true
  265. }
  266. func (e TypeReflectCacheEntry) getUnstructuredConverter(v reflect.Value) (UnstructuredConverter, bool) {
  267. if e.isStringConvertable {
  268. return v.Interface().(UnstructuredConverter), true
  269. }
  270. if e.ptrIsStringConvertable {
  271. // Check pointer receivers if v is not a pointer
  272. if v.CanAddr() {
  273. v = v.Addr()
  274. return v.Interface().(UnstructuredConverter), true
  275. }
  276. }
  277. return nil, false
  278. }
  279. type typeReflectCache struct {
  280. // use an atomic and copy-on-write since there are a fixed (typically very small) number of structs compiled into any
  281. // go program using this cache
  282. value atomic.Value
  283. // mu is held by writers when performing load/modify/store operations on the cache, readers do not need to hold a
  284. // read-lock since the atomic value is always read-only
  285. mu sync.Mutex
  286. }
  287. func newReflectCache() *typeReflectCache {
  288. cache := &typeReflectCache{}
  289. cache.value.Store(make(reflectCacheMap))
  290. return cache
  291. }
  292. type reflectCacheMap map[reflect.Type]*TypeReflectCacheEntry
  293. // get returns the reflectCacheMap.
  294. func (c *typeReflectCache) get() reflectCacheMap {
  295. return c.value.Load().(reflectCacheMap)
  296. }
  297. // update merges the provided updates into the cache.
  298. func (c *typeReflectCache) update(updates reflectCacheMap) {
  299. c.mu.Lock()
  300. defer c.mu.Unlock()
  301. currentCacheMap := c.value.Load().(reflectCacheMap)
  302. hasNewEntries := false
  303. for t := range updates {
  304. if _, ok := currentCacheMap[t]; !ok {
  305. hasNewEntries = true
  306. break
  307. }
  308. }
  309. if !hasNewEntries {
  310. // Bail if the updates have been set while waiting for lock acquisition.
  311. // This is safe since setting entries is idempotent.
  312. return
  313. }
  314. newCacheMap := make(reflectCacheMap, len(currentCacheMap)+len(updates))
  315. for k, v := range currentCacheMap {
  316. newCacheMap[k] = v
  317. }
  318. for t, update := range updates {
  319. newCacheMap[t] = update
  320. }
  321. c.value.Store(newCacheMap)
  322. }
  323. // Below json Unmarshal is fromk8s.io/apimachinery/pkg/util/json
  324. // to handle number conversions as expected by Kubernetes
  325. // limit recursive depth to prevent stack overflow errors
  326. const maxDepth = 10000
  327. // unmarshal unmarshals the given data
  328. // If v is a *map[string]interface{}, numbers are converted to int64 or float64
  329. func unmarshal(data []byte, v interface{}) error {
  330. switch v := v.(type) {
  331. case *map[string]interface{}:
  332. // Build a decoder from the given data
  333. decoder := json.NewDecoder(bytes.NewBuffer(data))
  334. // Preserve numbers, rather than casting to float64 automatically
  335. decoder.UseNumber()
  336. // Run the decode
  337. if err := decoder.Decode(v); err != nil {
  338. return err
  339. }
  340. // If the decode succeeds, post-process the map to convert json.Number objects to int64 or float64
  341. return convertMapNumbers(*v, 0)
  342. case *[]interface{}:
  343. // Build a decoder from the given data
  344. decoder := json.NewDecoder(bytes.NewBuffer(data))
  345. // Preserve numbers, rather than casting to float64 automatically
  346. decoder.UseNumber()
  347. // Run the decode
  348. if err := decoder.Decode(v); err != nil {
  349. return err
  350. }
  351. // If the decode succeeds, post-process the map to convert json.Number objects to int64 or float64
  352. return convertSliceNumbers(*v, 0)
  353. default:
  354. return json.Unmarshal(data, v)
  355. }
  356. }
  357. // convertMapNumbers traverses the map, converting any json.Number values to int64 or float64.
  358. // values which are map[string]interface{} or []interface{} are recursively visited
  359. func convertMapNumbers(m map[string]interface{}, depth int) error {
  360. if depth > maxDepth {
  361. return fmt.Errorf("exceeded max depth of %d", maxDepth)
  362. }
  363. var err error
  364. for k, v := range m {
  365. switch v := v.(type) {
  366. case json.Number:
  367. m[k], err = convertNumber(v)
  368. case map[string]interface{}:
  369. err = convertMapNumbers(v, depth+1)
  370. case []interface{}:
  371. err = convertSliceNumbers(v, depth+1)
  372. }
  373. if err != nil {
  374. return err
  375. }
  376. }
  377. return nil
  378. }
  379. // convertSliceNumbers traverses the slice, converting any json.Number values to int64 or float64.
  380. // values which are map[string]interface{} or []interface{} are recursively visited
  381. func convertSliceNumbers(s []interface{}, depth int) error {
  382. if depth > maxDepth {
  383. return fmt.Errorf("exceeded max depth of %d", maxDepth)
  384. }
  385. var err error
  386. for i, v := range s {
  387. switch v := v.(type) {
  388. case json.Number:
  389. s[i], err = convertNumber(v)
  390. case map[string]interface{}:
  391. err = convertMapNumbers(v, depth+1)
  392. case []interface{}:
  393. err = convertSliceNumbers(v, depth+1)
  394. }
  395. if err != nil {
  396. return err
  397. }
  398. }
  399. return nil
  400. }
  401. // convertNumber converts a json.Number to an int64 or float64, or returns an error
  402. func convertNumber(n json.Number) (interface{}, error) {
  403. // Attempt to convert to an int64 first
  404. if i, err := n.Int64(); err == nil {
  405. return i, nil
  406. }
  407. // Return a float64 (default json.Decode() behavior)
  408. // An overflow will return an error
  409. return n.Float64()
  410. }