1
16
17 package value
18
19 import (
20 "bytes"
21 "encoding/json"
22 "fmt"
23 "reflect"
24 "sort"
25 "sync"
26 "sync/atomic"
27 )
28
29
30
31
32
33 type UnstructuredConverter interface {
34 json.Marshaler
35
36
37 ToUnstructured() interface{}
38 }
39
40
41 type TypeReflectCacheEntry struct {
42 isJsonMarshaler bool
43 ptrIsJsonMarshaler bool
44 isJsonUnmarshaler bool
45 ptrIsJsonUnmarshaler bool
46 isStringConvertable bool
47 ptrIsStringConvertable bool
48
49 structFields map[string]*FieldCacheEntry
50 orderedStructFields []*FieldCacheEntry
51 }
52
53
54
55 type FieldCacheEntry struct {
56
57 JsonName string
58
59 isOmitEmpty bool
60
61
62
63 fieldPath [][]int
64
65 fieldType reflect.Type
66 TypeEntry *TypeReflectCacheEntry
67 }
68
69 func (f *FieldCacheEntry) CanOmit(fieldVal reflect.Value) bool {
70 return f.isOmitEmpty && (safeIsNil(fieldVal) || isZero(fieldVal))
71 }
72
73
74 func (f *FieldCacheEntry) GetFrom(structVal reflect.Value) reflect.Value {
75
76 for _, elem := range f.fieldPath {
77 structVal = dereference(structVal).FieldByIndex(elem)
78 }
79 return structVal
80 }
81
82 var marshalerType = reflect.TypeOf(new(json.Marshaler)).Elem()
83 var unmarshalerType = reflect.TypeOf(new(json.Unmarshaler)).Elem()
84 var unstructuredConvertableType = reflect.TypeOf(new(UnstructuredConverter)).Elem()
85 var defaultReflectCache = newReflectCache()
86
87
88 func TypeReflectEntryOf(t reflect.Type) *TypeReflectCacheEntry {
89 cm := defaultReflectCache.get()
90 if record, ok := cm[t]; ok {
91 return record
92 }
93 updates := reflectCacheMap{}
94 result := typeReflectEntryOf(cm, t, updates)
95 if len(updates) > 0 {
96 defaultReflectCache.update(updates)
97 }
98 return result
99 }
100
101
102
103 func typeReflectEntryOf(cm reflectCacheMap, t reflect.Type, updates reflectCacheMap) *TypeReflectCacheEntry {
104 if record, ok := cm[t]; ok {
105 return record
106 }
107 if record, ok := updates[t]; ok {
108 return record
109 }
110 typeEntry := &TypeReflectCacheEntry{
111 isJsonMarshaler: t.Implements(marshalerType),
112 ptrIsJsonMarshaler: reflect.PtrTo(t).Implements(marshalerType),
113 isJsonUnmarshaler: reflect.PtrTo(t).Implements(unmarshalerType),
114 isStringConvertable: t.Implements(unstructuredConvertableType),
115 ptrIsStringConvertable: reflect.PtrTo(t).Implements(unstructuredConvertableType),
116 }
117 if t.Kind() == reflect.Struct {
118 fieldEntries := map[string]*FieldCacheEntry{}
119 buildStructCacheEntry(t, fieldEntries, nil)
120 typeEntry.structFields = fieldEntries
121 sortedByJsonName := make([]*FieldCacheEntry, len(fieldEntries))
122 i := 0
123 for _, entry := range fieldEntries {
124 sortedByJsonName[i] = entry
125 i++
126 }
127 sort.Slice(sortedByJsonName, func(i, j int) bool {
128 return sortedByJsonName[i].JsonName < sortedByJsonName[j].JsonName
129 })
130 typeEntry.orderedStructFields = sortedByJsonName
131 }
132
133
134
135 updates[t] = typeEntry
136
137 for _, field := range typeEntry.structFields {
138 if field.TypeEntry == nil {
139 field.TypeEntry = typeReflectEntryOf(cm, field.fieldType, updates)
140 }
141 }
142 return typeEntry
143 }
144
145 func buildStructCacheEntry(t reflect.Type, infos map[string]*FieldCacheEntry, fieldPath [][]int) {
146 for i := 0; i < t.NumField(); i++ {
147 field := t.Field(i)
148 jsonName, omit, isInline, isOmitempty := lookupJsonTags(field)
149 if omit {
150 continue
151 }
152 if isInline {
153 e := field.Type
154 if field.Type.Kind() == reflect.Ptr {
155 e = field.Type.Elem()
156 }
157 if e.Kind() == reflect.Struct {
158 buildStructCacheEntry(e, infos, append(fieldPath, field.Index))
159 }
160 continue
161 }
162 info := &FieldCacheEntry{JsonName: jsonName, isOmitEmpty: isOmitempty, fieldPath: append(fieldPath, field.Index), fieldType: field.Type}
163 infos[jsonName] = info
164 }
165 }
166
167
168 func (e TypeReflectCacheEntry) Fields() map[string]*FieldCacheEntry {
169 return e.structFields
170 }
171
172
173 func (e TypeReflectCacheEntry) OrderedFields() []*FieldCacheEntry {
174 return e.orderedStructFields
175 }
176
177
178 func (e TypeReflectCacheEntry) CanConvertToUnstructured() bool {
179 return e.isJsonMarshaler || e.ptrIsJsonMarshaler || e.isStringConvertable || e.ptrIsStringConvertable
180 }
181
182
183 func (e TypeReflectCacheEntry) ToUnstructured(sv reflect.Value) (interface{}, error) {
184
185
186
187
188
189 if converter, ok := e.getUnstructuredConverter(sv); ok {
190 return converter.ToUnstructured(), nil
191 }
192
193 if marshaler, ok := e.getJsonMarshaler(sv); ok {
194 if sv.Kind() == reflect.Ptr && sv.IsNil() {
195
196 return nil, nil
197 }
198
199 data, err := marshaler.MarshalJSON()
200 if err != nil {
201 return nil, err
202 }
203 switch {
204 case len(data) == 0:
205 return nil, fmt.Errorf("error decoding from json: empty value")
206
207 case bytes.Equal(data, nullBytes):
208
209 return nil, nil
210
211 case bytes.Equal(data, trueBytes):
212 return true, nil
213
214 case bytes.Equal(data, falseBytes):
215 return false, nil
216
217 case data[0] == '"':
218 var result string
219 err := unmarshal(data, &result)
220 if err != nil {
221 return nil, fmt.Errorf("error decoding string from json: %v", err)
222 }
223 return result, nil
224
225 case data[0] == '{':
226 result := make(map[string]interface{})
227 err := unmarshal(data, &result)
228 if err != nil {
229 return nil, fmt.Errorf("error decoding object from json: %v", err)
230 }
231 return result, nil
232
233 case data[0] == '[':
234 result := make([]interface{}, 0)
235 err := unmarshal(data, &result)
236 if err != nil {
237 return nil, fmt.Errorf("error decoding array from json: %v", err)
238 }
239 return result, nil
240
241 default:
242 var (
243 resultInt int64
244 resultFloat float64
245 err error
246 )
247 if err = unmarshal(data, &resultInt); err == nil {
248 return resultInt, nil
249 } else if err = unmarshal(data, &resultFloat); err == nil {
250 return resultFloat, nil
251 } else {
252 return nil, fmt.Errorf("error decoding number from json: %v", err)
253 }
254 }
255 }
256
257 return nil, fmt.Errorf("provided type cannot be converted: %v", sv.Type())
258 }
259
260
261 func (e TypeReflectCacheEntry) CanConvertFromUnstructured() bool {
262 return e.isJsonUnmarshaler
263 }
264
265
266 func (e TypeReflectCacheEntry) FromUnstructured(sv, dv reflect.Value) error {
267
268
269 st := dv.Type()
270 data, err := json.Marshal(sv.Interface())
271 if err != nil {
272 return fmt.Errorf("error encoding %s to json: %v", st.String(), err)
273 }
274 if unmarshaler, ok := e.getJsonUnmarshaler(dv); ok {
275 return unmarshaler.UnmarshalJSON(data)
276 }
277 return fmt.Errorf("unable to unmarshal %v into %v", sv.Type(), dv.Type())
278 }
279
280 var (
281 nullBytes = []byte("null")
282 trueBytes = []byte("true")
283 falseBytes = []byte("false")
284 )
285
286 func (e TypeReflectCacheEntry) getJsonMarshaler(v reflect.Value) (json.Marshaler, bool) {
287 if e.isJsonMarshaler {
288 return v.Interface().(json.Marshaler), true
289 }
290 if e.ptrIsJsonMarshaler {
291
292 if v.Kind() != reflect.Ptr && v.CanAddr() {
293 v = v.Addr()
294 return v.Interface().(json.Marshaler), true
295 }
296 }
297 return nil, false
298 }
299
300 func (e TypeReflectCacheEntry) getJsonUnmarshaler(v reflect.Value) (json.Unmarshaler, bool) {
301 if !e.isJsonUnmarshaler {
302 return nil, false
303 }
304 return v.Addr().Interface().(json.Unmarshaler), true
305 }
306
307 func (e TypeReflectCacheEntry) getUnstructuredConverter(v reflect.Value) (UnstructuredConverter, bool) {
308 if e.isStringConvertable {
309 return v.Interface().(UnstructuredConverter), true
310 }
311 if e.ptrIsStringConvertable {
312
313 if v.CanAddr() {
314 v = v.Addr()
315 return v.Interface().(UnstructuredConverter), true
316 }
317 }
318 return nil, false
319 }
320
321 type typeReflectCache struct {
322
323
324 value atomic.Value
325
326
327 mu sync.Mutex
328 }
329
330 func newReflectCache() *typeReflectCache {
331 cache := &typeReflectCache{}
332 cache.value.Store(make(reflectCacheMap))
333 return cache
334 }
335
336 type reflectCacheMap map[reflect.Type]*TypeReflectCacheEntry
337
338
339 func (c *typeReflectCache) get() reflectCacheMap {
340 return c.value.Load().(reflectCacheMap)
341 }
342
343
344 func (c *typeReflectCache) update(updates reflectCacheMap) {
345 c.mu.Lock()
346 defer c.mu.Unlock()
347
348 currentCacheMap := c.value.Load().(reflectCacheMap)
349
350 hasNewEntries := false
351 for t := range updates {
352 if _, ok := currentCacheMap[t]; !ok {
353 hasNewEntries = true
354 break
355 }
356 }
357 if !hasNewEntries {
358
359
360 return
361 }
362
363 newCacheMap := make(reflectCacheMap, len(currentCacheMap)+len(updates))
364 for k, v := range currentCacheMap {
365 newCacheMap[k] = v
366 }
367 for t, update := range updates {
368 newCacheMap[t] = update
369 }
370 c.value.Store(newCacheMap)
371 }
372
373
374
375
376
377 const maxDepth = 10000
378
379
380
381 func unmarshal(data []byte, v interface{}) error {
382 switch v := v.(type) {
383 case *map[string]interface{}:
384
385 decoder := json.NewDecoder(bytes.NewBuffer(data))
386
387 decoder.UseNumber()
388
389 if err := decoder.Decode(v); err != nil {
390 return err
391 }
392
393 return convertMapNumbers(*v, 0)
394
395 case *[]interface{}:
396
397 decoder := json.NewDecoder(bytes.NewBuffer(data))
398
399 decoder.UseNumber()
400
401 if err := decoder.Decode(v); err != nil {
402 return err
403 }
404
405 return convertSliceNumbers(*v, 0)
406
407 default:
408 return json.Unmarshal(data, v)
409 }
410 }
411
412
413
414 func convertMapNumbers(m map[string]interface{}, depth int) error {
415 if depth > maxDepth {
416 return fmt.Errorf("exceeded max depth of %d", maxDepth)
417 }
418
419 var err error
420 for k, v := range m {
421 switch v := v.(type) {
422 case json.Number:
423 m[k], err = convertNumber(v)
424 case map[string]interface{}:
425 err = convertMapNumbers(v, depth+1)
426 case []interface{}:
427 err = convertSliceNumbers(v, depth+1)
428 }
429 if err != nil {
430 return err
431 }
432 }
433 return nil
434 }
435
436
437
438 func convertSliceNumbers(s []interface{}, depth int) error {
439 if depth > maxDepth {
440 return fmt.Errorf("exceeded max depth of %d", maxDepth)
441 }
442
443 var err error
444 for i, v := range s {
445 switch v := v.(type) {
446 case json.Number:
447 s[i], err = convertNumber(v)
448 case map[string]interface{}:
449 err = convertMapNumbers(v, depth+1)
450 case []interface{}:
451 err = convertSliceNumbers(v, depth+1)
452 }
453 if err != nil {
454 return err
455 }
456 }
457 return nil
458 }
459
460
461 func convertNumber(n json.Number) (interface{}, error) {
462
463 if i, err := n.Int64(); err == nil {
464 return i, nil
465 }
466
467
468 return n.Float64()
469 }
470
View as plain text