Skip to content

Instantly share code, notes, and snippets.

@shovon
Last active July 28, 2019 16:08
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save shovon/c3f0530482d854210524ee84775ebaa3 to your computer and use it in GitHub Desktop.
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
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