Skip to content

Commit bc3185d

Browse files
committed
Add Caller to update bean source location
1 parent af615b8 commit bc3185d

File tree

5 files changed

+77
-58
lines changed

5 files changed

+77
-58
lines changed

gs/app.go

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -208,17 +208,21 @@ func (app *App) Accept(b *BeanDefinition) *BeanDefinition {
208208

209209
// Object register object bean to Ioc container.
210210
func (app *App) Object(i interface{}) *BeanDefinition {
211-
return app.container.Accept(NewBean(reflect.ValueOf(i)))
211+
return app.container.Accept(NewBean(reflect.ValueOf(i)).Caller(2))
212212
}
213213

214214
// Provide register method bean to Ioc container.
215215
func (app *App) Provide(ctor interface{}, args ...arg.Arg) *BeanDefinition {
216-
return app.container.Accept(NewBean(ctor, args...))
216+
return app.container.Accept(NewBean(ctor, args...).Caller(2))
217217
}
218218

219219
// Configuration scan that the object `i` has `NewXXX` methods to Ioc container.
220220
func (app *App) Configuration(i interface{}) *BeanDefinition {
221-
return app.container.Configuration(i)
221+
bd, ok := i.(*BeanDefinition)
222+
if !ok {
223+
bd = NewBean(i).Caller(2)
224+
}
225+
return app.container.Configuration(bd)
222226
}
223227

224228
// AllowCircularReferences enable circular-references.

gs/boot.go

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -61,17 +61,17 @@ func Accept(b *BeanDefinition) *BeanDefinition {
6161

6262
// Object register bean to Ioc container.
6363
func Object(i interface{}) *BeanDefinition {
64-
return bootApp.Accept(NewBean(reflect.ValueOf(i)))
64+
return bootApp.Accept(NewBean(reflect.ValueOf(i)).Caller(2))
6565
}
6666

6767
// Provide register bean to Ioc container.
6868
func Provide(ctor interface{}, args ...arg.Arg) *BeanDefinition {
69-
return bootApp.Accept(NewBean(ctor, args...))
69+
return bootApp.Accept(NewBean(ctor, args...).Caller(2))
7070
}
7171

7272
// Configuration scan the object `i` has `NewXXX` methods to Ioc container.
7373
func Configuration(i interface{}) *BeanDefinition {
74-
return bootApp.Configuration(i)
74+
return bootApp.Configuration(NewBean(reflect.ValueOf(i)).Caller(2))
7575
}
7676

7777
// Go start a goroutine managed by the IoC container.

gs/gs.go

Lines changed: 24 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ import (
2424
"fmt"
2525
"log/slog"
2626
"reflect"
27+
"runtime"
2728
"runtime/debug"
2829
"sort"
2930
"strings"
@@ -175,12 +176,12 @@ func (c *container) Accept(b *BeanDefinition) *BeanDefinition {
175176

176177
// Object register object bean to Ioc container.
177178
func (c *container) Object(i interface{}) *BeanDefinition {
178-
return c.Accept(NewBean(reflect.ValueOf(i)))
179+
return c.Accept(NewBean(reflect.ValueOf(i)).Caller(2))
179180
}
180181

181182
// Provide register method bean to Ioc container.
182183
func (c *container) Provide(ctor interface{}, args ...arg.Arg) *BeanDefinition {
183-
return c.Accept(NewBean(ctor, args...))
184+
return c.Accept(NewBean(ctor, args...).Caller(2))
184185
}
185186

186187
// AllowCircularReferences enable circular-references.
@@ -201,10 +202,13 @@ func (c *container) AllowCircularReferences() {
201202
// func(x *T) NewServer() *gs.BeanDefinition
202203
func (c *container) Configuration(i interface{}) *BeanDefinition {
203204

204-
bValue := reflect.ValueOf(i)
205-
bType := bValue.Type()
205+
parentBean, ok := i.(*BeanDefinition)
206+
if !ok {
207+
parentBean = NewBean(i).Caller(2)
208+
}
206209

207-
parentBean := c.Accept(NewBean(bValue))
210+
bValue := parentBean.Value()
211+
bType := parentBean.Type()
208212

209213
for j := 0; j < bType.NumMethod(); j++ {
210214
method := bType.Method(j)
@@ -215,7 +219,7 @@ func (c *container) Configuration(i interface{}) *BeanDefinition {
215219
var bd *BeanDefinition
216220

217221
switch method.Type.NumOut() {
218-
case 1: // func(x *T) NewFoo() *Foo
222+
case 1:
219223
outType := method.Type.Out(0)
220224
if !utils.IsBeanType(outType) {
221225
continue
@@ -231,6 +235,12 @@ func (c *container) Configuration(i interface{}) *BeanDefinition {
231235
bd = c.Accept(bdInst.(*BeanDefinition))
232236
} else {
233237
bd = c.Provide(method.Func.Interface())
238+
// fix caller information
239+
if f := runtime.FuncForPC(method.Func.Pointer()); nil != f {
240+
bd.file, bd.line = f.FileLine(f.Entry())
241+
} else {
242+
bd.file, bd.line = parentBean.file, parentBean.line
243+
}
234244
}
235245
case 2:
236246
out0Type := method.Type.Out(0)
@@ -257,16 +267,20 @@ func (c *container) Configuration(i interface{}) *BeanDefinition {
257267
bd = c.Accept(bdInst.(*BeanDefinition))
258268
} else {
259269
bd = c.Provide(method.Func.Interface())
270+
// fix caller information
271+
if f := runtime.FuncForPC(method.Func.Pointer()); nil != f {
272+
bd.file, bd.line = f.FileLine(f.Entry())
273+
} else {
274+
bd.file, bd.line = parentBean.file, parentBean.line
275+
}
260276
}
261277
}
262278

263-
// 修改注册行号信息为父级bean注册位置
264-
bd.file, bd.line = parentBean.file, parentBean.line
265-
// 依赖父级bean
279+
// depends on parent bean
266280
bd.DependsOn(parentBean.ID()).On(cond.OnBean(parentBean.ID()))
267281
}
268282

269-
return parentBean
283+
return c.Accept(parentBean)
270284
}
271285

272286
// Dependencies return the dependency order list in either ascending or descending order.

gs/gs_bean.go

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -239,13 +239,21 @@ func (d *BeanDefinition) Destroy(fn interface{}) *BeanDefinition {
239239
panic(errors.New("destroy should be func(bean) or func(bean)error"))
240240
}
241241

242-
// Export 设置 bean 的导出接口。
242+
// Export indicates the types of interface to export.
243243
func (d *BeanDefinition) Export(exports ...interface{}) *BeanDefinition {
244244
err := d.export(exports...)
245245
utils.Panic(err).When(err != nil)
246246
return d
247247
}
248248

249+
// Caller update bean register point on source file:line.
250+
func (d *BeanDefinition) Caller(skip int) *BeanDefinition {
251+
if _, file, line, ok := runtime.Caller(skip); ok {
252+
d.file, d.line = file, line
253+
}
254+
return d
255+
}
256+
249257
func (d *BeanDefinition) export(exports ...interface{}) error {
250258
for _, o := range exports {
251259
var typ reflect.Type
@@ -326,9 +334,8 @@ func NewBean(objOrCtor interface{}, ctorArgs ...arg.Arg) *BeanDefinition {
326334
panic(errors.New("bean can't be nil"))
327335
}
328336

329-
const skip = 2
330337
var f *arg.Callable
331-
_, file, line, _ := runtime.Caller(skip)
338+
_, file, line, _ := runtime.Caller(1)
332339

333340
// 以 reflect.ValueOf(fn) 形式注册的函数被视为函数对象 bean 。
334341
if !fromValue && t.Kind() == reflect.Func {
@@ -340,7 +347,7 @@ func NewBean(objOrCtor interface{}, ctorArgs ...arg.Arg) *BeanDefinition {
340347
}
341348

342349
var err error
343-
f, err = arg.Bind(objOrCtor, ctorArgs, skip)
350+
f, err = arg.Bind(objOrCtor, ctorArgs, 1)
344351
utils.Panic(err).When(err != nil)
345352

346353
out0 := t.Out(0)

gs/gs_bean_test.go

Lines changed: 32 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -23,18 +23,12 @@ import (
2323
"reflect"
2424
"testing"
2525

26-
"github.com/go-spring-projects/go-spring/gs/arg"
2726
pkg1 "github.com/go-spring-projects/go-spring/gs/testdata/pkg/bar"
2827
pkg2 "github.com/go-spring-projects/go-spring/gs/testdata/pkg/foo"
2928
"github.com/go-spring-projects/go-spring/internal/utils"
3029
"github.com/go-spring-projects/go-spring/internal/utils/assert"
3130
)
3231

33-
// newBean 该方法是为了平衡调用栈的深度,一般情况下 gs.NewBean 不应该被直接使用。
34-
func newBean(objOrCtor interface{}, ctorArgs ...arg.Arg) *BeanDefinition {
35-
return NewBean(objOrCtor, ctorArgs...)
36-
}
37-
3832
//func TestParseSingletonTag(t *testing.T) {
3933
//
4034
// data := map[string]SingletonTag{
@@ -112,18 +106,18 @@ func TestBeanDefinition_Match(t *testing.T) {
112106
beanName string
113107
expect bool
114108
}{
115-
{newBean(new(pkg2.SamePkg)), "github.com/go-spring-projects/go-spring/gs/testdata/pkg/foo/pkg.SamePkg", "SamePkg", true},
116-
{newBean(new(pkg2.SamePkg)), "", "SamePkg", true},
117-
{newBean(new(pkg2.SamePkg)), "github.com/go-spring-projects/go-spring/gs/testdata/pkg/foo/pkg.SamePkg", "", true},
118-
{newBean(new(pkg2.SamePkg)).Name("pkg2"), "github.com/go-spring-projects/go-spring/gs/testdata/pkg/foo/pkg.SamePkg", "pkg2", true},
119-
{newBean(new(pkg2.SamePkg)).Name("pkg2"), "", "pkg2", true},
120-
{newBean(new(pkg2.SamePkg)).Name("pkg2"), "github.com/go-spring-projects/go-spring/gs/testdata/pkg/foo/pkg.SamePkg", "pkg2", true},
121-
{newBean(new(pkg1.SamePkg)), "github.com/go-spring-projects/go-spring/gs/testdata/pkg/bar/pkg.SamePkg", "SamePkg", true},
122-
{newBean(new(pkg1.SamePkg)), "", "SamePkg", true},
123-
{newBean(new(pkg1.SamePkg)), "github.com/go-spring-projects/go-spring/gs/testdata/pkg/bar/pkg.SamePkg", "", true},
124-
{newBean(new(pkg1.SamePkg)).Name("pkg1"), "github.com/go-spring-projects/go-spring/gs/testdata/pkg/bar/pkg.SamePkg", "pkg1", true},
125-
{newBean(new(pkg1.SamePkg)).Name("pkg1"), "", "pkg1", true},
126-
{newBean(new(pkg1.SamePkg)).Name("pkg1"), "github.com/go-spring-projects/go-spring/gs/testdata/pkg/bar/pkg.SamePkg", "pkg1", true},
109+
{NewBean(new(pkg2.SamePkg)), "github.com/go-spring-projects/go-spring/gs/testdata/pkg/foo/pkg.SamePkg", "SamePkg", true},
110+
{NewBean(new(pkg2.SamePkg)), "", "SamePkg", true},
111+
{NewBean(new(pkg2.SamePkg)), "github.com/go-spring-projects/go-spring/gs/testdata/pkg/foo/pkg.SamePkg", "", true},
112+
{NewBean(new(pkg2.SamePkg)).Name("pkg2"), "github.com/go-spring-projects/go-spring/gs/testdata/pkg/foo/pkg.SamePkg", "pkg2", true},
113+
{NewBean(new(pkg2.SamePkg)).Name("pkg2"), "", "pkg2", true},
114+
{NewBean(new(pkg2.SamePkg)).Name("pkg2"), "github.com/go-spring-projects/go-spring/gs/testdata/pkg/foo/pkg.SamePkg", "pkg2", true},
115+
{NewBean(new(pkg1.SamePkg)), "github.com/go-spring-projects/go-spring/gs/testdata/pkg/bar/pkg.SamePkg", "SamePkg", true},
116+
{NewBean(new(pkg1.SamePkg)), "", "SamePkg", true},
117+
{NewBean(new(pkg1.SamePkg)), "github.com/go-spring-projects/go-spring/gs/testdata/pkg/bar/pkg.SamePkg", "", true},
118+
{NewBean(new(pkg1.SamePkg)).Name("pkg1"), "github.com/go-spring-projects/go-spring/gs/testdata/pkg/bar/pkg.SamePkg", "pkg1", true},
119+
{NewBean(new(pkg1.SamePkg)).Name("pkg1"), "", "pkg1", true},
120+
{NewBean(new(pkg1.SamePkg)).Name("pkg1"), "github.com/go-spring-projects/go-spring/gs/testdata/pkg/bar/pkg.SamePkg", "pkg1", true},
127121
}
128122

129123
for i, s := range data {
@@ -161,12 +155,12 @@ func TestObjectBean(t *testing.T) {
161155
t.Run("bean must be ref type", func(t *testing.T) {
162156

163157
data := []func(){
164-
func() { newBean([...]int{0}) },
165-
func() { newBean(false) },
166-
func() { newBean(3) },
167-
func() { newBean("3") },
168-
func() { newBean(BeanZero{}) },
169-
func() { newBean(pkg2.SamePkg{}) },
158+
func() { NewBean([...]int{0}) },
159+
func() { NewBean(false) },
160+
func() { NewBean(3) },
161+
func() { NewBean("3") },
162+
func() { NewBean(BeanZero{}) },
163+
func() { NewBean(pkg2.SamePkg{}) },
170164
}
171165

172166
for _, fn := range data {
@@ -175,9 +169,9 @@ func TestObjectBean(t *testing.T) {
175169
})
176170

177171
t.Run("valid bean", func(t *testing.T) {
178-
newBean(make(chan int))
179-
newBean(reflect.ValueOf(func() {}))
180-
newBean(&BeanZero{})
172+
NewBean(make(chan int))
173+
NewBean(reflect.ValueOf(func() {}))
174+
NewBean(&BeanZero{})
181175
})
182176

183177
t.Run("check name && typename", func(t *testing.T) {
@@ -186,21 +180,21 @@ func TestObjectBean(t *testing.T) {
186180
name string
187181
typeName string
188182
}{
189-
newBean(io.Writer(os.Stdout)): {
183+
NewBean(io.Writer(os.Stdout)): {
190184
"File", "os/os.File",
191185
},
192186

193-
newBean(newHistoryTeacher("")): {
187+
NewBean(newHistoryTeacher("")): {
194188
"historyTeacher",
195189
"github.com/go-spring-projects/go-spring/gs/gs.historyTeacher",
196190
},
197191

198-
newBean(new(pkg2.SamePkg)): {
192+
NewBean(new(pkg2.SamePkg)): {
199193
"SamePkg",
200194
"github.com/go-spring-projects/go-spring/gs/testdata/pkg/foo/pkg.SamePkg",
201195
},
202196

203-
newBean(new(pkg2.SamePkg)).Name("pkg2"): {
197+
NewBean(new(pkg2.SamePkg)).Name("pkg2"): {
204198
"pkg2",
205199
"github.com/go-spring-projects/go-spring/gs/testdata/pkg/foo/pkg.SamePkg",
206200
},
@@ -215,30 +209,30 @@ func TestObjectBean(t *testing.T) {
215209

216210
func TestConstructorBean(t *testing.T) {
217211

218-
bd := newBean(NewStudent)
212+
bd := NewBean(NewStudent)
219213
assert.Equal(t, bd.Type().String(), "*gs.Student")
220214

221-
bd = newBean(NewPtrStudent)
215+
bd = NewBean(NewPtrStudent)
222216
assert.Equal(t, bd.Type().String(), "*gs.Student")
223217

224218
//mapFn := func() map[int]string { return make(map[int]string) }
225-
//bd = newBean(mapFn)
219+
//bd = NewBean(mapFn)
226220
//assert.Equal(t, bd.Type().String(), "*map[int]string")
227221

228222
//sliceFn := func() []int { return make([]int, 1) }
229-
//bd = newBean(sliceFn)
223+
//bd = NewBean(sliceFn)
230224
//assert.Equal(t, bd.Type().String(), "*[]int")
231225

232226
funcFn := func() func(int) { return nil }
233-
bd = newBean(funcFn)
227+
bd = NewBean(funcFn)
234228
assert.Equal(t, bd.Type().String(), "func(int)")
235229

236230
interfaceFn := func(name string) Teacher { return newHistoryTeacher(name) }
237-
bd = newBean(interfaceFn)
231+
bd = NewBean(interfaceFn)
238232
assert.Equal(t, bd.Type().String(), "gs.Teacher")
239233

240234
assert.Panic(t, func() {
241-
_ = newBean(func() (*int, *int) { return nil, nil })
235+
_ = NewBean(func() (*int, *int) { return nil, nil })
242236
}, "constructor should be func\\(...\\)bean or func\\(...\\)\\(bean, error\\)")
243237
}
244238

0 commit comments

Comments
 (0)