This repository has been archived by the owner on Oct 22, 2021. It is now read-only.
/
serialization_helper.go
95 lines (84 loc) · 2.42 KB
/
serialization_helper.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
package util
import (
"encoding/json"
"fmt"
"reflect"
"strings"
)
// The Marshaler interface is implemented by types which require custom
// marshalling support for dumping as JSON / YAML
type Marshaler interface {
Marshal() (interface{}, error)
}
// JSONMarshal marshals an arbitrary map to JSON; this only exists because
// JSON.Marshal insists on having maps that have string (and not interface{})
// keys
func JSONMarshal(input interface{}) ([]byte, error) {
converted, err := jsonMarshalHelper(input)
if err != nil {
return nil, err
}
return json.Marshal(converted)
}
type jsonMarshalError struct {
msg string
keys []string
}
func (e jsonMarshalError) Error() string {
return fmt.Sprintf("Error marshalling JSON: Failed to convert keys in path %s: %s",
strings.Join(e.keys, "."), e.msg)
}
// jsonMarshalHelper converts a map from having interface{} keys to string keys
func jsonMarshalHelper(input interface{}) (interface{}, *jsonMarshalError) {
value := reflect.ValueOf(input)
switch value.Kind() {
case reflect.Map:
result := make(map[string]interface{})
for _, keyValue := range value.MapKeys() {
keyInterface := keyValue.Interface()
keyString, ok := keyInterface.(string)
if !ok {
return nil, &jsonMarshalError{msg: fmt.Sprintf("Invalid key %#v", keyInterface)}
}
valueInterface := value.MapIndex(keyValue).Interface()
convertedValue, err := jsonMarshalHelper(valueInterface)
if err != nil {
err.keys = append([]string{keyString}, err.keys...)
return nil, err
}
result[keyString] = convertedValue
}
return result, nil
case reflect.Array, reflect.Slice:
var result []interface{}
for i := 0; i < value.Len(); i++ {
element, err := jsonMarshalHelper(value.Index(i).Interface())
if err != nil {
return nil, err
}
result = append(result, element)
}
return result, nil
default:
return input, nil
}
}
type marshalAdapter struct {
object Marshaler
}
// MarshalJSON implements the encoding/json.Marshal interface
func (a *marshalAdapter) MarshalJSON() ([]byte, error) {
result, err := a.object.Marshal()
if err != nil {
return nil, err
}
return json.Marshal(result)
}
// MarshalYAML implements the yaml.Marshal interface
func (a *marshalAdapter) MarshalYAML() (interface{}, error) {
return a.object.Marshal()
}
// NewMarshalAdapter creates a new adapter for JSON/YAML marshalling
func NewMarshalAdapter(m Marshaler) interface{} {
return &marshalAdapter{m}
}