reflectcache.go 15 KB

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