mirror of
https://github.com/zeromicro/go-zero.git
synced 2026-05-07 15:10:01 +08:00
fix: unmarshal problem on env vars for type env string (#5037)
Signed-off-by: kevin <wanjunfeng@gmail.com> Signed-off-by: Kevin Wan <wanjunfeng@gmail.com>
This commit is contained in:
@@ -30,9 +30,7 @@ var (
|
||||
errValueNotSettable = errors.New("value is not settable")
|
||||
errValueNotStruct = errors.New("value type is not struct")
|
||||
keyUnmarshaler = NewUnmarshaler(defaultKeyName)
|
||||
boolType = reflect.TypeOf(false)
|
||||
durationType = reflect.TypeOf(time.Duration(0))
|
||||
stringType = reflect.TypeOf("")
|
||||
cacheKeys = make(map[string][]string)
|
||||
cacheKeysLock sync.Mutex
|
||||
defaultCache = make(map[string]any)
|
||||
@@ -768,23 +766,25 @@ func (u *Unmarshaler) processFieldWithEnvValue(fieldType reflect.Type, value ref
|
||||
}
|
||||
|
||||
derefType := Deref(fieldType)
|
||||
switch derefType {
|
||||
case boolType:
|
||||
derefKind := derefType.Kind()
|
||||
switch {
|
||||
case derefKind == reflect.String:
|
||||
SetValue(fieldType, value, toReflectValue(derefType, envVal))
|
||||
return nil
|
||||
case derefKind == reflect.Bool:
|
||||
val, err := strconv.ParseBool(envVal)
|
||||
if err != nil {
|
||||
return fmt.Errorf("unmarshal field %q with environment variable, %w", fullName, err)
|
||||
}
|
||||
|
||||
SetValue(fieldType, value, reflect.ValueOf(val))
|
||||
SetValue(fieldType, value, toReflectValue(derefType, val))
|
||||
return nil
|
||||
case durationType:
|
||||
case derefType == durationType:
|
||||
// time.Duration is a special case, its derefKind is reflect.Int64.
|
||||
if err := fillDurationValue(fieldType, value, envVal); err != nil {
|
||||
return fmt.Errorf("unmarshal field %q with environment variable, %w", fullName, err)
|
||||
}
|
||||
|
||||
return nil
|
||||
case stringType:
|
||||
SetValue(fieldType, value, reflect.ValueOf(envVal))
|
||||
return nil
|
||||
default:
|
||||
return u.processFieldPrimitiveWithJSONNumber(fieldType, value, json.Number(envVal), opts, fullName)
|
||||
|
||||
@@ -6083,6 +6083,105 @@ func TestParseJsonStringValue(t *testing.T) {
|
||||
})
|
||||
}
|
||||
|
||||
// issue #5033, string type
|
||||
func TestUnmarshalFromEnvString(t *testing.T) {
|
||||
t.Setenv("STRING_ENV", "dev")
|
||||
|
||||
t.Run("by value", func(t *testing.T) {
|
||||
type (
|
||||
Env string
|
||||
Config struct {
|
||||
Env Env `json:",env=STRING_ENV,default=prod"`
|
||||
}
|
||||
)
|
||||
|
||||
var c Config
|
||||
if assert.NoError(t, UnmarshalJsonMap(map[string]any{}, &c)) {
|
||||
assert.Equal(t, Env("dev"), c.Env)
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("by ptr", func(t *testing.T) {
|
||||
type (
|
||||
Env string
|
||||
Config struct {
|
||||
Env *Env `json:",env=STRING_ENV,default=prod"`
|
||||
}
|
||||
)
|
||||
|
||||
var c Config
|
||||
if assert.NoError(t, UnmarshalJsonMap(map[string]any{}, &c)) {
|
||||
assert.Equal(t, Env("dev"), *c.Env)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
// issue #5033, bool type
|
||||
func TestUnmarshalFromEnvBool(t *testing.T) {
|
||||
t.Setenv("BOOL_ENV", "true")
|
||||
|
||||
t.Run("by value", func(t *testing.T) {
|
||||
type (
|
||||
Env bool
|
||||
Config struct {
|
||||
Env Env `json:",env=BOOL_ENV,default=false"`
|
||||
}
|
||||
)
|
||||
|
||||
var c Config
|
||||
if assert.NoError(t, UnmarshalJsonMap(map[string]any{}, &c)) {
|
||||
assert.Equal(t, Env(true), c.Env)
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("by ptr", func(t *testing.T) {
|
||||
type (
|
||||
Env bool
|
||||
Config struct {
|
||||
Env *Env `json:",env=BOOL_ENV,default=false"`
|
||||
}
|
||||
)
|
||||
|
||||
var c Config
|
||||
if assert.NoError(t, UnmarshalJsonMap(map[string]any{}, &c)) {
|
||||
assert.Equal(t, Env(true), *c.Env)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
// issue #5033, customized int type
|
||||
func TestUnmarshalFromEnvInt(t *testing.T) {
|
||||
t.Setenv("INT_ENV", "2")
|
||||
|
||||
t.Run("by value", func(t *testing.T) {
|
||||
type (
|
||||
Env int
|
||||
Config struct {
|
||||
Env Env `json:",env=INT_ENV,default=0"`
|
||||
}
|
||||
)
|
||||
|
||||
var c Config
|
||||
if assert.NoError(t, UnmarshalJsonMap(map[string]any{}, &c)) {
|
||||
assert.Equal(t, Env(2), c.Env)
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("by ptr", func(t *testing.T) {
|
||||
type (
|
||||
Env int
|
||||
Config struct {
|
||||
Env *Env `json:",env=INT_ENV,default=0"`
|
||||
}
|
||||
)
|
||||
|
||||
var c Config
|
||||
if assert.NoError(t, UnmarshalJsonMap(map[string]any{}, &c)) {
|
||||
assert.Equal(t, Env(2), *c.Env)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
func BenchmarkDefaultValue(b *testing.B) {
|
||||
for i := 0; i < b.N; i++ {
|
||||
var a struct {
|
||||
|
||||
@@ -583,6 +583,10 @@ func toFloat64(v any) (float64, bool) {
|
||||
}
|
||||
}
|
||||
|
||||
func toReflectValue(tp reflect.Type, v any) reflect.Value {
|
||||
return reflect.ValueOf(v).Convert(Deref(tp))
|
||||
}
|
||||
|
||||
func usingDifferentKeys(key string, field reflect.StructField) bool {
|
||||
if len(field.Tag) > 0 {
|
||||
if _, ok := field.Tag.Lookup(key); !ok {
|
||||
|
||||
Reference in New Issue
Block a user