michael.schuett
michael.schuett

Reputation: 4771

Golang Null Types and json.Decode()

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

Answers (2)

julienc
julienc

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:

  • If 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.
  • If 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

OneOfOne
OneOfOne

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

Related Questions