Jagdish Idhate
Jagdish Idhate

Reputation: 7742

Default value golang struct using `encoding/json` ?

How to set default value for Encoding as "base64"?

type FileData struct {
    UID string `json:"uid"`                 
    Size int `json:"size"`
    Content string `json:content`
    Encoding string `json:encoding` 
    User string `json:"user"`
}

I tried

Encoding string `json:encoding`= "base64" // Not working

Upvotes: 19

Views: 70306

Answers (4)

Son Bui
Son Bui

Reputation: 341

You can set default value when you init your 'FileData'
See my example: https://play.golang.org/p/QXwDG7_mul
Page int has default value 33

package main

import (
    "encoding/json"
    "fmt"
)

type Response2 struct {
    Page   int      `json:"page"`
    Fruits []string `json:"fruits"`
}

func main() {
    str := `{"fruits": ["apple", "peach"]}`
    res := Response2{Page: 33 /*Default value*/}
    json.Unmarshal([]byte(str), &res)
    fmt.Println(res)
}

Upvotes: 26

Pankaj Yadav
Pankaj Yadav

Reputation: 147

If there is a need to read the struct values from environment variables, then "github.com/kelseyhightower/envconfig" library can be used and then you can declare your struct as below:

type FileData struct {
    UID string `envconfig:"uid"`                 
    Size int `envconfig:"size"`
    Content string `envconfig:content`
    Encoding string `envconfig:encoding default:"base64"` 
    User string `envconfig:"user"`
}

You can finally unmarshal JSON to your struct.

Note: I know this is not what you asked for, but this might help someone.

Upvotes: 1

kostix
kostix

Reputation: 55443

You can't because in Go types do not have constructors.

Instead, have either an explicit initializer function (or method on the pointer receiver) or a constructor/factory function (these are conventionally called New<TypeName> so yours would be NewFileData) which would return an initialized value of your type.

All-in-all, I have a feeling this looks like an XY problem. From your question, it appears you want to have a default value on one of your fields if nothing was unmarshaled. If so, just post-process the values of this type unmarshaled from JSON and if nothing was unmarshaled to Encodning set it to whatever default you want.

Alternatively you might consider this approach:

  1. Have a custom type for your field.

    Something like type EncodingMethod string should do.

  2. Have a custom JSON unmarshaling method for this type which would do whatever handling it wants.

Upvotes: 7

abhink
abhink

Reputation: 9116

Since your FileData isn't too complex, you can easily make use of json.Unmarshaler interface. Declare Encoding as a separate type and set the default value in the unmarshal method:

type FileData struct {
    UID string `json:"uid"`                 
    Size int `json:"size"`
    Content string `json:content`
    Encoding Encoding `json:encoding` // declared as a custom type
    User string `json:"user"`
}

type Encoding string

// implement the Unmarshaler interface on Encoding
func (e *Encoding) UnmarshalJSON(b []byte) error {
    var s string
    if err := json.Unmarshal(b, &s); err != nil {
        return err
    }
    if s == "" {
        *e = Encoding("base64")
    } else {
        *e = Encoding(s)
    }
    return nil
}

Now when you encode a json with empty Encoding value, it'll be set to base64:

var data1 = []byte(`{"uid": "UID", "size": 10, "content": "CONTENT", "encoding": "ASCII", "user": "qwe"}`)
var data2 = []byte(`{"uid": "UID", "size": 10, "content": "CONTENT", "encoding": "", "user": "qwe"}`)

func main() {
    fmt.Println("Hello, playground")
    f := FileData{}
    if e := json.Unmarshal(data1, &f); e != nil {
        fmt.Println("Error:", e)
    }
    fmt.Println(f, f.Encoding)
    if e := json.Unmarshal(data2, &f); e != nil {
        fmt.Println("Error:", e)
    }
    fmt.Println(f, f.Encoding)
}

Output:

{UID 10 CONTENT ASCII qwe} ASCII
{UID 10 CONTENT base64 qwe} base64

Working code: https://play.golang.org/p/y5_wBgHGJk

Upvotes: 13

Related Questions