5

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

2 Answers 2

10

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)
        }
    }
}
Sign up to request clarification or add additional context in comments.

2 Comments

Thank you, this will work perfect for what I need. I am still trying to get use to go typing after coming from Java it's a very different though process.
My tip is completely forget everything you learning from Java, also forget that language ever existed. Go is by far the fastest and cleanest language I've ever learned.
0

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]]

5 Comments

Well, if the json has null values then it shouldn't be a problem, it means the value isn't set anyway.
You may be right, I don't see any good example with null values in json indeed...
Unless you want to use keys as boolean, for instance: "isdebug": null would mean true and "" would mean false (I agree it would be a very bad idea to do so though).
Yes that is a good point. I think that will be a limitation i will document though that you need to use a bool for what is essentially a t/f value.
There is one use case where it is important to distinguish null from not specified: implementing JSON Merge Patch as specified in rfc7386

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.