JSON - integer unmarshal field in string

I am struggling with deserializing an integer in a string structure field. The struct field is a string and is expected to be assigned from users of my library. Therefore, I want it to be a string, because to write it in the database, I really still do not care about the value inside. Users can provide text, but some simply assign integers.

Consider this structure:

type Test struct {
  Foo string
}

Sometimes I get a JSON value that is valid but will not be deserialized into the structure because the Foo field is an integer instead of a string:

{ "foo": "1" } // works
{ "foo": 1 } // doesn't

json.Unmarshal will explode with the following error: json: cannot unmarshal number into Go struct field test.Foo of type string

Watch playback: https://play.golang.org/p/4Qau3umaVm

JSON ( ) , , , int . Go?

, , json.Unmarshal - Foo interface{}, ..

, ? json:",string"

+4
2

.

, , , .

func (t *T) UnmarshalJSON(d []byte) error {
    type T2 T // create new type with same structure as T but without its method set!
    x := struct{
        T2 // embed
        Foo json.Number `json:"foo"`
    }{T2: T2(*t)} // don't forget this, if you do and 't' already has some fields set you would lose them

    if err := json.Unmarshal(d, &x); err != nil {
        return err
    }
    *t = T(x.T2)
    t.Foo = x.Foo.String()
    return nil
}

https://play.golang.org/p/BytXCeHMvt

+5

, , json.Unamrshaler.

nnmarshal JSON :

type test struct {
    Foo string `json:"foo"`
}

func (t *test) UnmarshalJSON(d []byte) error {
    tmp := struct {
        Foo interface{} `json:"foo"`
    }{}

    if err := json.Unmarshal(d, &tmp); err != nil {
        return err
    }

    switch v := tmp.Foo.(type) {
    case float64:
        t.Foo = strconv.Itoa(int(v))
    case string:
        t.Foo = v
    default:
        return fmt.Errorf("invalid value for Foo: %v", v)
    }

    return nil
}

https://play.golang.org/p/t0eI4wCxdB

+1

Source: https://habr.com/ru/post/1684775/


All Articles