Last active
July 28, 2019 16:08
-
-
Save shovon/c3f0530482d854210524ee84775ebaa3 to your computer and use it in GitHub Desktop.
`IsZero` is potentially a method that can be called in order to determine if an instance of a struct is a "zero value". json.Marshal, however, does not yet implement this, and so, this is a solution to the problem, for now
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package lib | |
import ( | |
"encoding/json" | |
"reflect" | |
"strings" | |
) | |
// IsZeroer implement this if you want some special definition of "zero" | |
type IsZeroer interface { | |
IsZero() bool | |
} | |
// IsZeroOfUnderlyingType is the underlying type a "zero"? | |
func isZeroOfUnderlyingType(x interface{}) bool { | |
isZero := x == reflect.Zero(reflect.TypeOf(x)).Interface() | |
zeroer, ok := x.(IsZeroer) | |
return (ok && zeroer.IsZero()) || isZero | |
} | |
// MarshalJSONOmitEmpty omit all "empty" values. | |
func MarshalJSONOmitEmpty(value interface{}) ([]byte, error) { | |
// Get the type. | |
t := reflect.TypeOf(value) | |
valueOf := reflect.ValueOf(value) | |
values := make(map[string]interface{}) | |
// Iterate through the fields. | |
for i := 0; i < t.NumField(); i++ { | |
// Get the field name. | |
fieldName := t.Field(i).Name | |
value := reflect.Indirect(valueOf).FieldByName(fieldName).Interface() | |
jsonTag, ok := t.Field(i).Tag.Lookup("json") | |
var isString bool | |
var isOmitEmpty bool | |
if ok { | |
components := strings.Split(jsonTag, ",") | |
jsonName := strings.Trim(components[0], "\t\r\n ") | |
if jsonName == "-" && len(components) == 1 { | |
continue | |
} else if jsonName != "" { | |
fieldName = jsonName | |
} | |
if len(components) > 1 { | |
for _, tag := range components[1:] { | |
taggedTrimmed := strings.Trim(tag, "\t\r\n ") | |
switch taggedTrimmed { | |
case "omitempty": | |
isOmitEmpty = true | |
case "string": | |
isString = true | |
} | |
} | |
} | |
} | |
if isOmitEmpty && isZeroOfUnderlyingType(value) { | |
continue | |
} | |
if isString { | |
result, err := json.Marshal(value) | |
if err != nil { | |
return []byte{}, err | |
} | |
values[fieldName] = string(result) | |
} else { | |
values[fieldName] = value | |
} | |
} | |
return json.Marshal(values) | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment