8

I need to show json's empty object {} when do json.Marshal() for a struct pointer. I can only output either null value or empty struct value.

If the person key is filled with &Person{} or new(Person), it will show empty struct like below:

{
    "data": {
        "person": {
            "name": "",
            "age": 0
        },
        "created_date": "2009-11-10T23:00:00Z"
    }
}

And if we don't initialize it at all, it will show null.

{
    "data": {
        "person": null,
        "created_date": "2009-11-10T23:00:00Z"
    }
}

I want to show "person": {}. Is it possible?

Go Playground for the complete code: https://play.golang.org/p/tT15G2ESPVc

6
  • 3
    use omitempty for the Person's fields. play.golang.org/p/o3jWdru_8bC Commented May 2, 2018 at 14:22
  • 1
    another way you could handle this is by using a non-pointer wrapper type that embeds your Person pointer type, like so: play.golang.org/p/EKQc7uf1_Vk Commented May 2, 2018 at 14:37
  • @mkopriva using omitempty for the Person's fields has worked and by far the simplest. But it will affect my Person's fields encoding when I want to keep showing, for example, Person.name in the marshal result when it is empty Commented May 2, 2018 at 14:39
  • You can use the alternative in my second comment or you'll have to implement the Marshaler interface on the Response type, I think that's pretty much all the options you're left with. Commented May 2, 2018 at 14:42
  • this one's a bit ugly but works without having to compromise your original structure. play.golang.org/p/1qkSCWZ225j Commented May 2, 2018 at 14:48

2 Answers 2

12

Option A, use the omitempty tag option on all of the Person's fields and make sure the response's field is allocated before marshaling.

type Person struct {
    Name string `json:"name,omitempty"`
    Age  int    `json:"age,omitempty"`
}

// ...

resp.Person = new(Person)

https://play.golang.org/p/o3jWdru_8bC


Option B, use a non-pointer wrapper type that embeds the Person pointer type.

type PersonJSON struct {
    *Person
}

type Response struct {
    Person      PersonJSON `json:"person"`
    CreatedDate time.Time   `json:"created_date"`
}

https://play.golang.org/p/EKQc7uf1_Vk


Option C, have the Reponse type implement the json.Marshaler interface.

func (r *Response) MarshalJSON() ([]byte, error) {
    type tmp Response
    resp := (*tmp)(r)

    var data struct {
        Wrapper struct {
            *Person
        } `json:"person"`
        *tmp
    }
    data.Wrapper.Person = resp.Person
    data.tmp = resp
    return json.Marshal(data)
}

https://play.golang.org/p/1qkSCWZ225j


There may be other options...

Sign up to request clarification or add additional context in comments.

1 Comment

Great answer! Option B was just what I needed.
0

In Go, an empty struct by definition assigns zero values to field elements. Eg: for int 0, "" for string, etc.

For your case, simply comparing to null would work out. Or, you could define an emptyPerson as:

 var BAD_AGE = -1
 emptyPerson := &Person{"", BAD_AGE} // BAD_AGE indicates no person
 if person[age] == BAD_AGE {
    // handle case for emptyPerson}

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.