JSON unmarshaling with long numbers gives floating point number

Fersca picture Fersca · Mar 12, 2014 · Viewed 31.2k times · Source

I was marshaling and unmarshaling JSONs using golang and when I want to do it with number fields golang transforms it in floating point numbers instead of use long numbers, for example.

I have the following JSON:

{
    "id": 12423434, 
    "Name": "Fernando"
}

After marshal it to a map and unmarshal again to a json string I get:

{
    "id":1.2423434e+07,
    "Name":"Fernando"
}

As you can see the "id" field is in floating point notation.

The code that I am using is the following:

package main

import (
    "encoding/json"
    "fmt"
    "os"
)

func main() {

    //Create the Json string
    var b = []byte(`
        {
        "id": 12423434, 
        "Name": "Fernando"
        }
    `)

    //Marshal the json to a map
    var f interface{}
    json.Unmarshal(b, &f)
    m := f.(map[string]interface{})

    //print the map
    fmt.Println(m)

    //unmarshal the map to json
    result,_:= json.Marshal(m)

    //print the json
    os.Stdout.Write(result)

}

It prints:

map[id:1.2423434e+07 Name:Fernando]
{"Name":"Fernando","id":1.2423434e+07}

It appears to be that the first marshal to the map generates the FP. How can I fix it to a long?

This is the link to the program in the goland playground: http://play.golang.org/p/RRJ6uU4Uw-

Answer

rog picture rog · Mar 12, 2014

There are times when you cannot define a struct in advance but still require numbers to pass through the marshal-unmarshal process unchanged.

In that case you can use the UseNumber method on json.Decoder, which causes all numbers to unmarshal as json.Number (which is just the original string representation of the number). This can also useful for storing very big integers in JSON.

For example:

package main

import (
    "strings"
    "encoding/json"
    "fmt"
    "log"
)

var data = `{
    "id": 12423434, 
    "Name": "Fernando"
}`

func main() {
    d := json.NewDecoder(strings.NewReader(data))
    d.UseNumber()
    var x interface{}
    if err := d.Decode(&x); err != nil {
        log.Fatal(err)
    }
    fmt.Printf("decoded to %#v\n", x)
    result, err := json.Marshal(x)
    if err != nil {
        log.Fatal(err)
    }
    fmt.Printf("encoded to %s\n", result)
}

Result:

decoded to map[string]interface {}{"id":"12423434", "Name":"Fernando"}
encoded to {"Name":"Fernando","id":12423434}