diff --git a/gs/gs.go b/gs/gs.go index 1ff53b14..deaf26f2 100644 --- a/gs/gs.go +++ b/gs/gs.go @@ -243,6 +243,13 @@ func Config() *gs_conf.AppConfig { return gs_app.GS.P } +// Component registers a bean definition for a given object. +func Component[T any](i T) T { + b := gs_bean.NewBean(reflect.ValueOf(i)) + gs_app.GS.C.Register(b).Caller(1) + return i +} + // Object registers a bean definition for a given object. func Object(i interface{}) *RegisteredBean { b := gs_bean.NewBean(reflect.ValueOf(i)) diff --git a/gs/internal/gs_core/injecting/injecting_test.go b/gs/internal/gs_core/injecting/injecting_test.go index 00e8b352..e441be12 100644 --- a/gs/internal/gs_core/injecting/injecting_test.go +++ b/gs/internal/gs_core/injecting/injecting_test.go @@ -22,6 +22,7 @@ import ( "fmt" "net/http" "reflect" + "runtime" "testing" "time" @@ -927,20 +928,36 @@ type DyncValue struct { func TestForceClean(t *testing.T) { t.Run("no dync value", func(t *testing.T) { + release := make(map[string]struct{}) + r := New(conf.Map(map[string]interface{}{ "spring": map[string]interface{}{ "force-clean": true, }, })) - beans := []*gs.BeanDefinition{ - objectBean(&SimpleLogger{}).Name("biz"), - objectBean(&SimpleLogger{}).Name("sys"), - } + + b1 := objectBean(&SimpleLogger{}).Name("biz") + runtime.AddCleanup(&b1, func(s string) { + release[s] = struct{}{} + }, "biz") + + b2 := objectBean(&SimpleLogger{}).Name("sys") + runtime.AddCleanup(&b2, func(s string) { + release[s] = struct{}{} + }, "sys") + + beans := []*gs.BeanDefinition{b1, b2} err := r.Refresh(extractBeans(beans)) assert.Nil(t, err) assert.Nil(t, r.p) assert.Nil(t, r.beansByName) assert.Nil(t, r.beansByType) + + runtime.GC() + assert.That(t, release).Equal(map[string]struct{}{ + "biz": {}, + "sys": {}, + }) }) t.Run("has dync value", func(t *testing.T) { diff --git a/gs/internal/gs_dync/dync_test.go b/gs/internal/gs_dync/dync_test.go index cc34801a..248c6e16 100644 --- a/gs/internal/gs_dync/dync_test.go +++ b/gs/internal/gs_dync/dync_test.go @@ -181,4 +181,35 @@ func TestDync(t *testing.T) { assert.ThatError(t, err).Matches("strconv.ParseInt: parsing \\\"xyz\\\": invalid syntax") assert.That(t, p.ObjectsCount()).Equal(4) }) + + t.Run("refresh struct", func(t *testing.T) { + p := New(conf.Map(map[string]interface{}{ + "config.s1.value": "99", + })) + + v := &Value[struct { + S1 struct { + Value int `value:"${value}"` + } `value:"${s1}"` + }]{} + + var param conf.BindParam + err := param.BindTag("${config}", "") + assert.Nil(t, err) + + err = p.RefreshField(reflect.ValueOf(v), param) + assert.Nil(t, err) + assert.That(t, v.Value().S1.Value).Equal(99) + + err = p.Refresh(conf.Map(map[string]interface{}{ + "config.s1.value": "xyz", + })) + assert.ThatError(t, err).Matches("strconv.ParseInt: parsing \"xyz\": invalid syntax") + + err = p.Refresh(conf.Map(map[string]interface{}{ + "config.s1.value": "10", + })) + assert.Nil(t, err) + assert.That(t, v.Value().S1.Value).Equal(10) + }) }