-
Notifications
You must be signed in to change notification settings - Fork 0
/
omitempty.go
110 lines (92 loc) · 2.1 KB
/
omitempty.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
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
package omitempty
import (
"encoding/json"
"encoding/xml"
"reflect"
"strings"
)
type IsEmptier interface {
IsEmpty() bool
}
func MarshalJSON(obj interface{}) ([]byte, error) {
st := reflect.TypeOf(obj)
fs := []reflect.StructField{}
for i := 0; i < st.NumField(); i++ {
fs = append(fs, st.Field(i))
}
for i, _ := range fs {
if !fieldHasOmitEmpty(fs[i], "json") {
continue
}
val := reflect.ValueOf(obj)
valueField := val.Field(i)
f := valueField.Interface()
if isempty, ok := f.(IsEmptier); ok {
if !isempty.IsEmpty() {
continue
}
fs[i].Tag = reflect.StructTag(`json:"-"`)
}
continue
}
st2 := reflect.StructOf(fs)
v := reflect.ValueOf(obj)
v2 := v.Convert(st2)
return json.Marshal(v2.Interface())
}
func MarshalXML(obj interface{}, e *xml.Encoder, start xml.StartElement) error {
st := reflect.TypeOf(obj)
fs := []reflect.StructField{}
for i := 0; i < st.NumField(); i++ {
f := st.Field(i)
// skip unexported fields
if len(f.PkgPath) != 0 {
continue
}
fs = append(fs, f)
}
for i, _ := range fs {
if !fieldHasOmitEmpty(fs[i], "xml") {
continue
}
val := reflect.ValueOf(obj)
j := fs[i].Index[0]
valueField := val.Field(j)
f := valueField.Interface()
if isNil(f) {
fs[i].Tag = reflect.StructTag(`xml:"-"`)
continue
}
if isempty, ok := f.(IsEmptier); ok {
if !isempty.IsEmpty() {
continue
}
fs[i].Tag = reflect.StructTag(`xml:"-"`)
}
continue
}
st2 := reflect.StructOf(fs)
v := reflect.ValueOf(obj)
v2 := v.Convert(st2)
return e.EncodeElement(v2.Interface(), start)
}
func fieldHasOmitEmpty(field reflect.StructField, encoder string) bool {
// Get the field tag value
tag := field.Tag.Get(encoder)
options := strings.Split(tag, ",")
for _, option := range options {
if option == "omitempty" {
return true
}
}
return false
}
func isNil(a interface{}) bool {
if a == nil {
return true
}
// return a == reflect.Zero(reflect.TypeOf(a)).Interface()
return reflect.DeepEqual(a, reflect.Zero(reflect.TypeOf(a)).Interface())
// defer func() { recover() }()
// return a == nil || reflect.ValueOf(a).IsNil()
}