Skip to content

Option JSON serialization/deserialization does not handle the null case correctly #72

@AlisCode

Description

@AlisCode

Hi,

I believe something is wrong in the behavior of Option's UnmarshalJSON.
Say I have the very basic struct :

type Person struct {
	Name string
	Age  mo.Option[int]
}

and a test that ensures that the person can be serialized to JSON back and forth (roundtrip) :

func TestRoundtripJSONPerson(t *testing.T) {
	person := bugmooption.Person{
		Name: "MyPerson",
		Age:  mo.None[int](),
	}

	serialized, err := json.Marshal(&person)
        if err != nil {
		t.Fatalf("Failed to serialize Person")
	}

	var deserialized bugmooption.Person
	err := json.Unmarshal(serialized, &deserialized)
	if err != nil {
		t.Fatalf("Failed to deserialize Person")
	}

	if person != deserialized {
		t.Fatalf("person should be the same before and after JSON serialization roundtrip")
	}
}

The test currently fails. Indeed, after serializing, my person has a JSON field age: null.
After deserializing, I get an age which is of the form :

{
    value: 0,
    isPresent: true,
}

So I've had a look at the implementation. At a glance, this comment :

// if user manually set the field to be `null`, then `isPresent` should be `true` since that is want user intends the value to be
// this makes sure `isPresent` makes semantic sense, and solves the ambiguity of pointer completely

sounds very wrong to me. If the field is set to null, then I expect isPresent to be false, not true.

I'm not sure why no one else has found this behavior strange, am I missing something ?

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions