Reputation: 4771
I have not been able to find a way around this issue currently. If I have a structure i would like to populate with json from a http.Request I have no way to tell for instance what value was actually passed in for some values. For instance if I pass in an empty json object and run json.Decode on a structure that looks like this...
var Test struct {
Number int `json:"number"`
}
I now have a json object that supposedly was passed with a key of number and a value of zero when in fact I would rather have this return nothing at all. Does go provide another method that would actually allow me to see what JSON has been passed in or not.
Sorry for the rambling I have been trying to figure out how to to this for a few days now and it's driving me nuts.
Thanks for any help.
Edit:
I made this to depict exactly what I am talking about http://play.golang.org/p/aPFKSvuxC9
Upvotes: 4
Views: 9492
Reputation: 20325
I don't see how you could do this by giving a struct
to the Unmarshal
function. With the following structure for instance:
type A struct {
Hello string
Foo int
Baz string
}
var a A
json.Unmarshal(data, &a)
Even by doing another implementation of Unmarshal
, there would be only two (simple) possibilities:
baz
is not in the json data, set a.Baz
to a default value, compatible with its type: the empty string (or 0 if it's an integer). This is the current implementation.baz
is not in the json data, return an error. That would be very inconvenient if the absence of baz
is a normal behaviour.Another possibility would be to use pointers, and use the default value nil
in the same spirit than the default value I talked about, but there would still be issue if your json file could be filled with null
values: you would not be able to distinguish values that were in the json file, but set as null
, and values that were not in the json, and unmarshalled with nil
as their default value.
However, this solution might suit you: instead of using a struct
, why not using a map[string]interface{}
? The Unmarshall
function would not have to add a default value to non-present fields, and it would be able to retrieve any type of data from the json file.
var b = []byte(`[{"Name": "Platypus"}, {"Name": "Quoll", "Order": 100}]`)
var m []map[string]interface{}
err := json.Unmarshal(b, &m)
fmt.Println(m)
// [map[Name:Platypus] map[Name:Quoll Order:100]]
Upvotes: 0
Reputation: 99332
You could use pointers, for example:
func main() {
var jsonBlob = []byte(`[
{"Name": "Platypus"},
{"Name": "Quoll", "Order": 100}
]`)
type Animal struct {
Name string
Order *int
}
var animals []Animal
err := json.Unmarshal(jsonBlob, &animals)
if err != nil {
fmt.Println("error:", err)
}
for _, a := range animals {
if a.Order != nil {
fmt.Printf("got order, %s : %d\n", a.Name, *a.Order)
}
}
}
Upvotes: 10