Skip to content

fix: omitempty must not drop structs with non-zero unexported fields - #400

Open
sonnemusk wants to merge 1 commit into
vmihailenco:v5from
sonnemusk:fix/omitempty-unexported
Open

fix: omitempty must not drop structs with non-zero unexported fields#400
sonnemusk wants to merge 1 commit into
vmihailenco:v5from
sonnemusk:fix/omitempty-unexported

Conversation

@sonnemusk

Copy link
Copy Markdown

Problem

isEmptyValue decided whether a struct tagged omitempty was empty by scanning only exported fields (structs.Fields + OmitEmpty). A struct with zero-valued exported fields but non-zero unexported fields was incorrectly treated as empty and omitted, even though it is not the zero value of its type.

Minimal reproduction (#378)

type Val struct {
	content string
}

func (v Val) EncodeMsgpack(enc *msgpack.Encoder) error {
	return enc.EncodeString(v.content)
}

func (v *Val) DecodeMsgpack(dec *msgpack.Decoder) error {
	c, err := dec.DecodeString()
	if err != nil {
		return err
	}
	v.content = c
	return nil
}

type Foo struct {
	Val Val `msgpack:"val,omitempty"`
}

// Before: Val was omitted; round-trip lost "str".
foo := Foo{Val: Val{content: "str"}}

Fix

For reflect.Struct, use reflect.Value.IsZero, which checks all fields (exported and unexported). A struct is omitted only when it equals the zero value of its type.

Zero structs continue to be omitted; non-zero unexported state no longer causes data loss for exported fields or custom encoders.

Tests

All existing tests pass, including ExampleMarshal_ignore_simple_zero_structs_when_tagged_with_omitempty.

Fixes #378

Note on #390

#390 discusses broader omitempty vs encoding/json semantics (interface/any emptiness, future omitzero). This PR only fixes the unexported-field empty check from #378 and does not change interface/any omitempty behavior.

isEmptyValue for structs used exported fields only, so a value with
non-zero unexported state was treated as empty and omitted. Use
reflect.Value.IsZero so the check considers all fields.

Fixes vmihailenco#378
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

omitempty unexpectedly omits a member when the member is a struct with a non-zero unexported member

1 participant