Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

preserve int64 values when parsing json in Go

Tags:

json

parsing

go

I'm processing a json POST in Go that contains an array of objects containing 64bit integers. When using json.Unmarshal these values seem to be converted to a float64 which isn't very helpful.

body := []byte(`{"tags":[{"id":4418489049307132905},{"id":4418489049307132906}]}`)

var dat map[string]interface{}
if err := json.Unmarshal(body, &dat); err != nil {
    panic(err)
}

tags := dat["tags"].([]interface{})

for i, tag := range tags {

    fmt.Println("tag: ", i, " id: ", tag.(map[string]interface{})["id"].(int64))

}

Is there any way to preserve the original int64 in the output of json.Unmarshal?

Go Playground of above code

like image 681
sicr Avatar asked Jun 05 '13 17:06

sicr


1 Answers

Solution 1

You can use a Decoder and UseNumber to decode your numbers without loss :

The Number type is defined like this :

// A Number represents a JSON number literal.
type Number string

which means you can easily convert it :

package main

import (
    "encoding/json"
    "fmt"
    "bytes"
    "strconv"
)

func main() {
    body := []byte("{\"tags\":[{\"id\":4418489049307132905},{\"id\":4418489049307132906}]}")
    dat := make(map[string]interface{})
    d := json.NewDecoder(bytes.NewBuffer(body))
    d.UseNumber()
    if err := d.Decode(&dat); err != nil {
        panic(err)
    }
    tags := dat["tags"].([]interface{})
    n := tags[0].(map[string]interface{})["id"].(json.Number)
    i64, _ := strconv.ParseUint(string(n), 10, 64)
    fmt.Println(i64) // prints 4418489049307132905
}

Solution 2

You can also decode into a specific structure tailored to your needs :

package main

import (
    "encoding/json"
    "fmt"
)

type A struct {
    Tags []map[string]uint64 // "tags"
}

func main() {
    body := []byte("{\"tags\":[{\"id\":4418489049307132905},{\"id\":4418489049307132906}]}")
    var a A
    if err := json.Unmarshal(body, &a); err != nil {
        panic(err)
    }
    fmt.Println(a.Tags[0]["id"]) // logs 4418489049307132905
}

Personally I generally prefer this solution which feels more structured and easier to maintain.

Caution

A small note if you use JSON because your application is partly in JavaScript : JavaScript has no 64 bits integers but only one number type, which is the IEEE754 double precision float. So you wouldn't be able to parse this JSON in JavaScript without loss using the standard parsing function.

like image 113
Denys Séguret Avatar answered Sep 18 '22 15:09

Denys Séguret