Cannot unmarshal string into Go value of type int64
Asked Answered
M

3

66

I have struct

type tySurvey struct {
    Id     int64            `json:"id,omitempty"`
    Name   string           `json:"name,omitempty"`
}

I do json.Marshal write JSON bytes in HTML page. jQuery modifies name field in object and encodes object using jQueries JSON.stringify and jQuery posts string to Go handler.

id field encoded as string.

Sent: {"id":1} Received: {"id":"1"}

Problem is that json.Unmarshal fails to unmarshal that JSON because id is not integer anymore.

json: cannot unmarshal string into Go value of type int64

What is best way to handle such data? I do not wish to manually convert every field. I wish to write compact, bug free code.

Quotes is not too bad. JavaScript does not work well with int64.

I would like to learn the easy way to unmarshal json with string values in int64 values.

Manaus answered 16/1, 2014 at 1:27 Comment(1)
Is there a way to know which field causes the problem ?Panatella
P
133

This is handled by adding ,string to your tag as follows:

type tySurvey struct {
   Id   int64  `json:"id,string,omitempty"`
   Name string `json:"name,omitempty"`
}

This can be found about halfway through the documentation for Marshal.

Please note that you cannot decode the empty string by specifying omitempty as it is only used when encoding.

Pliant answered 16/1, 2014 at 2:55 Comment(2)
This would work if id does not come in as integer. Otherwise, you'd get an error "invalid use of ,string struct tag..."Irra
Using ,string wouldn't work if the field come in either int or string. The program will nag at you for using it on an int field. Use json.Number struct tag instead solve the issue as pointed by the answer below: https://mcmap.net/q/295089/-cannot-unmarshal-string-into-go-value-of-type-int64Jellied
J
25

use json.Number

type tySurvey struct {
    Id     json.Number      `json:"id,omitempty"`
    Name   string           `json:"name,omitempty"`
}
Jeffryjeffy answered 24/9, 2020 at 10:16 Comment(1)
This is the correct answer. the accepted answer doesnt workLibation
K
2

You could also create a type alias for int or int64 and create a custom json unmarshaler Sample code:

Reference

// StringInt create a type alias for type int
type StringInt int

// UnmarshalJSON create a custom unmarshal for the StringInt
/// this helps us check the type of our value before unmarshalling it

func (st *StringInt) UnmarshalJSON(b []byte) error {
    //convert the bytes into an interface
    //this will help us check the type of our value
    //if it is a string that can be converted into a int we convert it
    ///otherwise we return an error
    var item interface{}
    if err := json.Unmarshal(b, &item); err != nil {
        return err
    }
    switch v := item.(type) {
    case int:
        *st = StringInt(v)
    case float64:
        *st = StringInt(int(v))
    case string:
        ///here convert the string into
        ///an integer
        i, err := strconv.Atoi(v)
        if err != nil {
            ///the string might not be of integer type
            ///so return an error
            return err

        }
        *st = StringInt(i)

    }
    return nil
}

func main() {

    type Item struct {
        Name   string    `json:"name"`
        ItemId StringInt `json:"item_id"`
    }
    jsonData := []byte(`{"name":"item 1","item_id":"30"}`)
    var item Item
    err := json.Unmarshal(jsonData, &item)
    if err != nil {
        log.Fatal(err)
    }
    fmt.Printf("%+v\n", item)

}



Knowling answered 25/4, 2021 at 7:46 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.