Skip to content

Commit d505fae

Browse files
authored
fix: unmarshal problem on env vars for type env string (#5037)
Signed-off-by: kevin <[email protected]> Signed-off-by: Kevin Wan <[email protected]>
1 parent 25f37ca commit d505fae

File tree

3 files changed

+112
-9
lines changed

3 files changed

+112
-9
lines changed

core/mapping/unmarshaler.go

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -30,9 +30,7 @@ var (
3030
errValueNotSettable = errors.New("value is not settable")
3131
errValueNotStruct = errors.New("value type is not struct")
3232
keyUnmarshaler = NewUnmarshaler(defaultKeyName)
33-
boolType = reflect.TypeOf(false)
3433
durationType = reflect.TypeOf(time.Duration(0))
35-
stringType = reflect.TypeOf("")
3634
cacheKeys = make(map[string][]string)
3735
cacheKeysLock sync.Mutex
3836
defaultCache = make(map[string]any)
@@ -768,23 +766,25 @@ func (u *Unmarshaler) processFieldWithEnvValue(fieldType reflect.Type, value ref
768766
}
769767

770768
derefType := Deref(fieldType)
771-
switch derefType {
772-
case boolType:
769+
derefKind := derefType.Kind()
770+
switch {
771+
case derefKind == reflect.String:
772+
SetValue(fieldType, value, toReflectValue(derefType, envVal))
773+
return nil
774+
case derefKind == reflect.Bool:
773775
val, err := strconv.ParseBool(envVal)
774776
if err != nil {
775777
return fmt.Errorf("unmarshal field %q with environment variable, %w", fullName, err)
776778
}
777779

778-
SetValue(fieldType, value, reflect.ValueOf(val))
780+
SetValue(fieldType, value, toReflectValue(derefType, val))
779781
return nil
780-
case durationType:
782+
case derefType == durationType:
783+
// time.Duration is a special case, its derefKind is reflect.Int64.
781784
if err := fillDurationValue(fieldType, value, envVal); err != nil {
782785
return fmt.Errorf("unmarshal field %q with environment variable, %w", fullName, err)
783786
}
784787

785-
return nil
786-
case stringType:
787-
SetValue(fieldType, value, reflect.ValueOf(envVal))
788788
return nil
789789
default:
790790
return u.processFieldPrimitiveWithJSONNumber(fieldType, value, json.Number(envVal), opts, fullName)

core/mapping/unmarshaler_test.go

Lines changed: 99 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6083,6 +6083,105 @@ func TestParseJsonStringValue(t *testing.T) {
60836083
})
60846084
}
60856085

6086+
// issue #5033, string type
6087+
func TestUnmarshalFromEnvString(t *testing.T) {
6088+
t.Setenv("STRING_ENV", "dev")
6089+
6090+
t.Run("by value", func(t *testing.T) {
6091+
type (
6092+
Env string
6093+
Config struct {
6094+
Env Env `json:",env=STRING_ENV,default=prod"`
6095+
}
6096+
)
6097+
6098+
var c Config
6099+
if assert.NoError(t, UnmarshalJsonMap(map[string]any{}, &c)) {
6100+
assert.Equal(t, Env("dev"), c.Env)
6101+
}
6102+
})
6103+
6104+
t.Run("by ptr", func(t *testing.T) {
6105+
type (
6106+
Env string
6107+
Config struct {
6108+
Env *Env `json:",env=STRING_ENV,default=prod"`
6109+
}
6110+
)
6111+
6112+
var c Config
6113+
if assert.NoError(t, UnmarshalJsonMap(map[string]any{}, &c)) {
6114+
assert.Equal(t, Env("dev"), *c.Env)
6115+
}
6116+
})
6117+
}
6118+
6119+
// issue #5033, bool type
6120+
func TestUnmarshalFromEnvBool(t *testing.T) {
6121+
t.Setenv("BOOL_ENV", "true")
6122+
6123+
t.Run("by value", func(t *testing.T) {
6124+
type (
6125+
Env bool
6126+
Config struct {
6127+
Env Env `json:",env=BOOL_ENV,default=false"`
6128+
}
6129+
)
6130+
6131+
var c Config
6132+
if assert.NoError(t, UnmarshalJsonMap(map[string]any{}, &c)) {
6133+
assert.Equal(t, Env(true), c.Env)
6134+
}
6135+
})
6136+
6137+
t.Run("by ptr", func(t *testing.T) {
6138+
type (
6139+
Env bool
6140+
Config struct {
6141+
Env *Env `json:",env=BOOL_ENV,default=false"`
6142+
}
6143+
)
6144+
6145+
var c Config
6146+
if assert.NoError(t, UnmarshalJsonMap(map[string]any{}, &c)) {
6147+
assert.Equal(t, Env(true), *c.Env)
6148+
}
6149+
})
6150+
}
6151+
6152+
// issue #5033, customized int type
6153+
func TestUnmarshalFromEnvInt(t *testing.T) {
6154+
t.Setenv("INT_ENV", "2")
6155+
6156+
t.Run("by value", func(t *testing.T) {
6157+
type (
6158+
Env int
6159+
Config struct {
6160+
Env Env `json:",env=INT_ENV,default=0"`
6161+
}
6162+
)
6163+
6164+
var c Config
6165+
if assert.NoError(t, UnmarshalJsonMap(map[string]any{}, &c)) {
6166+
assert.Equal(t, Env(2), c.Env)
6167+
}
6168+
})
6169+
6170+
t.Run("by ptr", func(t *testing.T) {
6171+
type (
6172+
Env int
6173+
Config struct {
6174+
Env *Env `json:",env=INT_ENV,default=0"`
6175+
}
6176+
)
6177+
6178+
var c Config
6179+
if assert.NoError(t, UnmarshalJsonMap(map[string]any{}, &c)) {
6180+
assert.Equal(t, Env(2), *c.Env)
6181+
}
6182+
})
6183+
}
6184+
60866185
func BenchmarkDefaultValue(b *testing.B) {
60876186
for i := 0; i < b.N; i++ {
60886187
var a struct {

core/mapping/utils.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -583,6 +583,10 @@ func toFloat64(v any) (float64, bool) {
583583
}
584584
}
585585

586+
func toReflectValue(tp reflect.Type, v any) reflect.Value {
587+
return reflect.ValueOf(v).Convert(Deref(tp))
588+
}
589+
586590
func usingDifferentKeys(key string, field reflect.StructField) bool {
587591
if len(field.Tag) > 0 {
588592
if _, ok := field.Tag.Lookup(key); !ok {

0 commit comments

Comments
 (0)