decode: do not modify the source data in HookTranslateKeys
This was causing a 'fatal error: concurrent map iteration and map write' with gateways
This commit is contained in:
parent
97808ce1d4
commit
0fb5e53d14
|
@ -44,21 +44,28 @@ func HookTranslateKeys(_, to reflect.Type, data interface{}) (interface{}, error
|
|||
}
|
||||
|
||||
rules := translationsForType(to)
|
||||
// Avoid making a copy if there are no translation rules
|
||||
if len(rules) == 0 {
|
||||
return data, nil
|
||||
}
|
||||
result := make(map[string]interface{}, len(source))
|
||||
for k, v := range source {
|
||||
lowerK := strings.ToLower(k)
|
||||
canonKey, ok := rules[lowerK]
|
||||
if !ok {
|
||||
result[k] = v
|
||||
continue
|
||||
}
|
||||
delete(source, k)
|
||||
|
||||
// if there is a value for the canonical key then keep it
|
||||
if _, ok := source[canonKey]; ok {
|
||||
if canonValue, ok := source[canonKey]; ok {
|
||||
// Assign the value for the case where canonKey == k
|
||||
result[canonKey] = canonValue
|
||||
continue
|
||||
}
|
||||
source[canonKey] = v
|
||||
result[canonKey] = v
|
||||
}
|
||||
return source, nil
|
||||
return result, nil
|
||||
}
|
||||
|
||||
// TODO: could be cached if it is too slow
|
||||
|
|
|
@ -178,6 +178,33 @@ func TestHookTranslateKeys_TargetStructHasPointerReceiver(t *testing.T) {
|
|||
require.Equal(t, expected, target, "decode metadata: %#v", md)
|
||||
}
|
||||
|
||||
func TestHookTranslateKeys_DoesNotModifySourceData(t *testing.T) {
|
||||
raw := map[string]interface{}{
|
||||
"S": map[string]interface{}{
|
||||
"None": "no translation",
|
||||
"OldOne": "value1",
|
||||
"oldtwo": "value2",
|
||||
},
|
||||
}
|
||||
|
||||
cfg := Config{}
|
||||
decoder, err := mapstructure.NewDecoder(&mapstructure.DecoderConfig{
|
||||
DecodeHook: HookTranslateKeys,
|
||||
Result: &cfg,
|
||||
})
|
||||
require.NoError(t, err)
|
||||
require.NoError(t, decoder.Decode(raw))
|
||||
|
||||
expected := map[string]interface{}{
|
||||
"S": map[string]interface{}{
|
||||
"None": "no translation",
|
||||
"OldOne": "value1",
|
||||
"oldtwo": "value2",
|
||||
},
|
||||
}
|
||||
require.Equal(t, raw, expected)
|
||||
}
|
||||
|
||||
type translateExample struct {
|
||||
FieldDefaultCanonical string `alias:"first"`
|
||||
FieldWithMapstructureTag string `alias:"second" mapstructure:"field_with_mapstruct_tag"`
|
||||
|
|
Loading…
Reference in New Issue