DecodeHook
diff --git a/mapstructure.go b/mapstructure.go
index dae28dd..20941e1 100644
--- a/mapstructure.go
+++ b/mapstructure.go
@@ -19,6 +19,14 @@
// DecoderConfig is the configuration that is used to create a new decoder
// and allows customization of various aspects of decoding.
type DecoderConfig struct {
+ // DecodeHook, if set, will be called before any decoding and any
+ // type conversion (if WeaklyTypedInput is on). This lets you modify
+ // the values before they're set down onto the resulting struct.
+ //
+ // If an error is returned, the entire decode will fail with that
+ // error.
+ DecodeHook func(reflect.Kind, reflect.Kind, interface{}) (interface{}, error)
+
// If ErrorUnused is true, then it is an error for there to exist
// keys in the original map that were unused in the decoding process
// (extra keys).
@@ -144,9 +152,17 @@
return nil
}
+ if d.config.DecodeHook != nil {
+ // We have a DecodeHook, so let's pre-process the data.
+ var err error
+ data, err = d.config.DecodeHook(d.getKind(dataVal), d.getKind(val), data)
+ if err != nil {
+ return err
+ }
+ }
+
var err error
dataKind := d.getKind(val)
-
switch dataKind {
case reflect.Bool:
err = d.decodeBool(name, data, val)
diff --git a/mapstructure_test.go b/mapstructure_test.go
index 53aa5f8..8d86099 100644
--- a/mapstructure_test.go
+++ b/mapstructure_test.go
@@ -219,6 +219,42 @@
}
}
+func TestDecode_DecodeHook(t *testing.T) {
+ t.Parallel()
+
+ input := map[string]interface{}{
+ "vint": "WHAT",
+ }
+
+ decodeHook := func(from reflect.Kind, to reflect.Kind, v interface{}) (interface{}, error) {
+ if from == reflect.String && to != reflect.String {
+ return 5, nil
+ }
+
+ return v, nil
+ }
+
+ var result Basic
+ config := &DecoderConfig{
+ DecodeHook: decodeHook,
+ Result: &result,
+ }
+
+ decoder, err := NewDecoder(config)
+ if err != nil {
+ t.Fatalf("err: %s", err)
+ }
+
+ err = decoder.Decode(input)
+ if err != nil {
+ t.Fatalf("got an err: %s", err)
+ }
+
+ if result.Vint != 5 {
+ t.Errorf("vint should be 5: %#v", result.Vint)
+ }
+}
+
func TestDecode_Nil(t *testing.T) {
t.Parallel()