Now, viper.Unmarshal use mapstructure.Decoder as the decoder.
So I need to change my struct tag to mapstructure, although my config file is YAML, and I set ConfigType to YAML too. This is too strange.
for example, #385
viper use mapstructure and it can be config by mapstructure.DecoderConfig, viper also export this option and you can set tag name or wharever your like like this:
viper.Unmarshal(rawVal, func(config *mapstructure.DecoderConfig) {
config.TagName = "yaml"
// do anything your like
})
viper use
mapstructureand it can be config bymapstructure.DecoderConfig, viper also export this option and you can set tag name or wharever your like like this:viper.Unmarshal(rawVal, func(config *mapstructure.DecoderConfig) { config.TagName = "yaml" // do anything your like })
Thanks a lot. @yore-new
But viper ,not user, does this maybe better, I think. TagName correspond with ConfigType as default. User can custom this by themselves
package main
import (
"bytes"
"fmt"
"time"
yaml "gopkg.in/yaml.v2"
"github.com/mitchellh/mapstructure"
"github.com/spf13/viper"
)
type CustomType time.Time
func (ct *CustomType) UnmarshalYAML(unmarshal func(interface{}) error) error {
var raw string
if err := unmarshal(&raw); err != nil {
return err
}
if t, err := time.Parse("2006.01.02", raw); err != nil {
return err
} else {
*ct = CustomType(t)
}
return nil
}
var confStr = `---
custom: 2018.12.31
`
type SS struct {
Custom CustomType
}
func main() {
confBuf := &bytes.Buffer{}
confBuf.WriteString(confStr)
v := viper.New()
v.SetConfigType("yaml")
_ = v.ReadConfig(confBuf)
fmt.Printf("raw: %v\n", v.AllSettings())
var s SS
v.Unmarshal(&s, func(config *mapstructure.DecoderConfig) {
config.TagName = "yaml"
})
fmt.Printf("unmarshal by viper: %v\n", s)
tmp, _ := yaml.Marshal(v.AllSettings())
yaml.Unmarshal(tmp, &s)
fmt.Printf("unmarshal by yaml: %v\n", s)
}
And custom type does not work.
When viper loads a configuration file (eg. a YAML file) it normalizes and unmarshals the data into a map[string]interface{}. From that point the configuration has nothing to do with yaml anymore. Viper does this so that configuration from various sources (defaults, environment variables, flags) can all be "merged" into a single structure.
When you call Unmarshal on viper, it simply maps this data to your structure. Thus any yaml tags and yaml unmarshaling are out of scope at this point and this is why mapstructure is a better fit, but you can rename it to something else, like config.
If you want to do manual unmarshaling (like in the above example), you can use decode hooks (explained in the mapstructure documentation).
I would advise against mixing yaml and viper unmarshaling in a single struct as it can easily lead to confusions.
Most helpful comment
viper use
mapstructureand it can be config bymapstructure.DecoderConfig, viper also export this option and you can set tag name or wharever your like like this: