Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Unmarshal/Marshal json with int set to 0 does not seem to work

Tags:

json

go

I am trying to parse a json object into a struct, but integer values set to 0 won't work.

q := []byte(`{"string":"this is a string", "integer": 0}`)

type Test struct {
    String string `json:"string,omitempty"`
    Integer int `json:"integer,omitempty"`
}    

var qq Test
if err := json.Unmarshal(q, &qq); err != nil {
   panic(err)
}

queryStr, err := json.Marshal(qq)
if err != nil {
    panic(err)
}
fmt.Println(string(queryStr))
// Output: {"string": "this is a string"}

if I set the integer to anything but 0, this works fine.

even if I Unmarshal the object and set the Integer field to 0, Marshalling it back removes the "integer" field.

Why? and how to get around this?

EDIT:

from what I gather from the comments, omitempty triggers when value is 0. So now the disappearance makes sense.

I'm parsing json, editing it and forwarding it to another service, so this is unfortunate, especially as field not present defaults to other values than 0, and I would prefer not having to feed in the defaults for the downstream API.

So is there a way to omit empty values but keep 0?

or change empty to something else?

Do I need to have 2 structs: one for input and one for output?

like image 636
MrE Avatar asked Jul 20 '16 17:07

MrE


3 Answers

Use a pointer for the fields, so that the zero value of the JSON type can be differentiated from the missing value.

type Test struct {
    String  *string `json:"string,omitempty"`
    Integer *int    `json:"integer,omitempty"`
}

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

like image 136
JimB Avatar answered Nov 12 '22 01:11

JimB


"omitempty" tag makes sense only for marshaling from struct to JSON. It skips empty values so they won't be in JSON. It doesn't affect unmarshaling in any way. Use pointers if you want to detect whether the field is specified in JSON or not. If the field is not specified, the pointer value will be nil.

like image 24
Vadim Petrov Avatar answered Nov 12 '22 01:11

Vadim Petrov


as the docs says in https://golang.org/pkg/encoding/json/#Marshal

Struct values encode as JSON objects. Each exported struct field becomes a member of the object unless

  • the field's tag is "-", or
  • the field is empty and its tag specifies the "omitempty" option. The empty values are false, 0, any nil pointer or interface value, and any array, slice, map, or string of length zero. The object's default key string is the struct field name but can be specified in the struct field's tag value. The "json" key in the struct field's tag value is the key name, followed by an optional comma and options.

so no, unless you implement your own marshaller for your struct

like image 3
Javier Neyra Avatar answered Nov 12 '22 01:11

Javier Neyra