helpers/mapstructure: turn panic while decoding to an error message

While there is more helpful information in a panic, this is confusing
to the user. With the amount of code using reflection, it seems better
to have clearer messages to help the user find the faulty section if
any.
This commit is contained in:
Vincent Bernat
2022-08-30 20:32:45 +02:00
parent 8eab4277c6
commit c3d2fc64f8
3 changed files with 65 additions and 7 deletions

View File

@@ -4,6 +4,8 @@
package helpers
import (
"fmt"
"reflect"
"strings"
"github.com/mitchellh/mapstructure"
@@ -26,16 +28,31 @@ func GetMapStructureDecoderConfig(config interface{}, hooks ...mapstructure.Deco
ErrorUnused: true,
WeaklyTypedInput: true,
MatchName: MapStructureMatchName,
DecodeHook: mapstructure.ComposeDecodeHookFunc(
mapstructure.ComposeDecodeHookFunc(hooks...),
mapstructure.ComposeDecodeHookFunc(mapstructureUnmarshallerHookFuncs...),
mapstructure.TextUnmarshallerHookFunc(),
mapstructure.StringToTimeDurationHookFunc(),
mapstructure.StringToSliceHookFunc(","),
DecodeHook: ProtectedDecodeHookFunc(
mapstructure.ComposeDecodeHookFunc(
mapstructure.ComposeDecodeHookFunc(hooks...),
mapstructure.ComposeDecodeHookFunc(mapstructureUnmarshallerHookFuncs...),
mapstructure.TextUnmarshallerHookFunc(),
mapstructure.StringToTimeDurationHookFunc(),
mapstructure.StringToSliceHookFunc(","),
),
),
}
}
// ProtectedDecodeHookFunc wraps a DecodeHookFunc to recover and returns an error on panic.
func ProtectedDecodeHookFunc(hook mapstructure.DecodeHookFunc) mapstructure.DecodeHookFunc {
return func(from, to reflect.Value) (v interface{}, err error) {
defer func() {
if r := recover(); r != nil {
v = nil
err = fmt.Errorf("internal error while parsing: %s", r)
}
}()
return mapstructure.DecodeHookExec(hook, from, to)
}
}
// MapStructureMatchName tells if map key and field names are equal.
func MapStructureMatchName(mapKey, fieldName string) bool {
key := strings.ToLower(strings.ReplaceAll(mapKey, "-", ""))