mirror of
https://github.com/kataras/iris.git
synced 2025-02-02 15:30:36 +01:00
New APIContainer.EnableStrictMode(bool) method. Read HISTORY.md
This commit is contained in:
parent
43079f75d2
commit
6219e57135
|
@ -28,6 +28,8 @@ The codebase for Dependency Injection, Internationalization and localization and
|
||||||
|
|
||||||
## Fixes and Improvements
|
## Fixes and Improvements
|
||||||
|
|
||||||
|
- New `APIContainer.EnableStrictMode(bool)` to disable automatic payload binding and panic on missing dependencies for exported struct'sfields or function's input parameters on MVC controller or hero function or PartyConfigurator.
|
||||||
|
|
||||||
- New `Party.PartyConfigure(relativePath string, partyReg ...PartyConfigurator) Party` helper, registers a children Party like `Party` and `PartyFunc` but instead it accepts a structure value which may contain one or more of the dependencies registered by `RegisterDependency` or `ConfigureContainer().RegisterDependency` methods and fills the unset/zero exported struct's fields respectfully (useful when the api's dependencies amount are too much to pass on a function).
|
- New `Party.PartyConfigure(relativePath string, partyReg ...PartyConfigurator) Party` helper, registers a children Party like `Party` and `PartyFunc` but instead it accepts a structure value which may contain one or more of the dependencies registered by `RegisterDependency` or `ConfigureContainer().RegisterDependency` methods and fills the unset/zero exported struct's fields respectfully (useful when the api's dependencies amount are too much to pass on a function).
|
||||||
|
|
||||||
- **New feature:** add the ability to set custom error handlers on path type parameters errors (existing or custom ones). Example Code:
|
- **New feature:** add the ability to set custom error handlers on path type parameters errors (existing or custom ones). Example Code:
|
||||||
|
|
|
@ -893,12 +893,22 @@ func (api *APIBuilder) PartyFunc(relativePath string, partyBuilderFunc func(p Pa
|
||||||
return p
|
return p
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type (
|
||||||
// PartyConfigurator is an interface which all child parties that are registered
|
// PartyConfigurator is an interface which all child parties that are registered
|
||||||
// through `PartyConfigure` should implement.
|
// through `PartyConfigure` should implement.
|
||||||
type PartyConfigurator interface {
|
PartyConfigurator interface {
|
||||||
Configure(parent Party)
|
Configure(parent Party)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// StrictlyPartyConfigurator is an optional interface which a `PartyConfigurator`
|
||||||
|
// can implement to make sure that all exported fields having a not-nin, non-zero
|
||||||
|
// value before server starts.
|
||||||
|
// StrictlyPartyConfigurator interface {
|
||||||
|
// Strict() bool
|
||||||
|
// }
|
||||||
|
// Good idea but a `mvc or bind:"required"` is a better one I think.
|
||||||
|
)
|
||||||
|
|
||||||
// PartyConfigure like `Party` and `PartyFunc` registers a new children Party
|
// PartyConfigure like `Party` and `PartyFunc` registers a new children Party
|
||||||
// but instead it accepts a struct value which should implement the PartyConfigurator interface.
|
// but instead it accepts a struct value which should implement the PartyConfigurator interface.
|
||||||
//
|
//
|
||||||
|
|
|
@ -79,6 +79,22 @@ func (api *APIContainer) UseResultHandler(handler func(next hero.ResultHandler)
|
||||||
return api
|
return api
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// EnableStrictMode sets the container's DisablePayloadAutoBinding and MarkExportedFieldsAsRequired to true.
|
||||||
|
// Meaning that all struct's fields (or function's parameters) should be binded manually (except the path parameters).
|
||||||
|
//
|
||||||
|
// Note that children will clone the same properties.
|
||||||
|
// Call the same method with `false` for children
|
||||||
|
// to enable automatic binding on missing dependencies.
|
||||||
|
//
|
||||||
|
// Strict mode is disabled by default;
|
||||||
|
// structs or path parameters that don't match to registered dependencies
|
||||||
|
// are automatically binded from the request context (body and url path parameters respectfully).
|
||||||
|
func (api *APIContainer) EnableStrictMode(strictMode bool) *APIContainer {
|
||||||
|
api.Container.DisablePayloadAutoBinding = strictMode
|
||||||
|
api.Container.MarkExportedFieldsAsRequired = strictMode
|
||||||
|
return api
|
||||||
|
}
|
||||||
|
|
||||||
// convertHandlerFuncs accepts Iris hero handlers and returns a slice of native Iris handlers.
|
// convertHandlerFuncs accepts Iris hero handlers and returns a slice of native Iris handlers.
|
||||||
func (api *APIContainer) convertHandlerFuncs(relativePath string, handlersFn ...interface{}) context.Handlers {
|
func (api *APIContainer) convertHandlerFuncs(relativePath string, handlersFn ...interface{}) context.Handlers {
|
||||||
fullpath := api.Self.GetRelPath() + relativePath
|
fullpath := api.Self.GetRelPath() + relativePath
|
||||||
|
|
|
@ -118,7 +118,7 @@ func matchDependency(dep *Dependency, in reflect.Type) bool {
|
||||||
return dep.DestType == nil || equalTypes(dep.DestType, in)
|
return dep.DestType == nil || equalTypes(dep.DestType, in)
|
||||||
}
|
}
|
||||||
|
|
||||||
func getBindingsFor(inputs []reflect.Type, deps []*Dependency, paramsCount int) (bindings []*binding) {
|
func getBindingsFor(inputs []reflect.Type, deps []*Dependency, disablePayloadAutoBinding bool, paramsCount int) (bindings []*binding) {
|
||||||
// Path parameter start index is the result of [total path parameters] - [total func path parameters inputs],
|
// Path parameter start index is the result of [total path parameters] - [total func path parameters inputs],
|
||||||
// moving from last to first path parameters and first to last (probably) available input args.
|
// moving from last to first path parameters and first to last (probably) available input args.
|
||||||
//
|
//
|
||||||
|
@ -208,15 +208,17 @@ func getBindingsFor(inputs []reflect.Type, deps []*Dependency, paramsCount int)
|
||||||
}
|
}
|
||||||
|
|
||||||
if prevN == len(bindings) {
|
if prevN == len(bindings) {
|
||||||
if canBePathParameter {
|
if canBePathParameter { // Let's keep that option just for "payload": disablePayloadAutoBinding
|
||||||
// no new dependency added for this input,
|
// no new dependency added for this input,
|
||||||
// let's check for path parameters.
|
// let's check for path parameters.
|
||||||
bindings = append(bindings, paramBinding(i, getParamIndex(), in))
|
bindings = append(bindings, paramBinding(i, getParamIndex(), in))
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
// else add builtin bindings that may be registered by user too, but they didn't.
|
// else, if payload binding is not disabled,
|
||||||
if isPayloadType(in) {
|
// add builtin request bindings that
|
||||||
|
// could be registered by end-dev but they didn't
|
||||||
|
if !disablePayloadAutoBinding && isPayloadType(in) {
|
||||||
bindings = append(bindings, payloadBinding(i, in))
|
bindings = append(bindings, payloadBinding(i, in))
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
@ -235,7 +237,7 @@ func isPayloadType(in reflect.Type) bool {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func getBindingsForFunc(fn reflect.Value, dependencies []*Dependency, paramsCount int) []*binding {
|
func getBindingsForFunc(fn reflect.Value, dependencies []*Dependency, disablePayloadAutoBinding bool, paramsCount int) []*binding {
|
||||||
fnTyp := fn.Type()
|
fnTyp := fn.Type()
|
||||||
if !isFunc(fnTyp) {
|
if !isFunc(fnTyp) {
|
||||||
panic("bindings: unresolved: not a func type")
|
panic("bindings: unresolved: not a func type")
|
||||||
|
@ -247,7 +249,7 @@ func getBindingsForFunc(fn reflect.Value, dependencies []*Dependency, paramsCoun
|
||||||
inputs[i] = fnTyp.In(i)
|
inputs[i] = fnTyp.In(i)
|
||||||
}
|
}
|
||||||
|
|
||||||
bindings := getBindingsFor(inputs, dependencies, paramsCount)
|
bindings := getBindingsFor(inputs, dependencies, disablePayloadAutoBinding, paramsCount)
|
||||||
if expected, got := n, len(bindings); expected != got {
|
if expected, got := n, len(bindings); expected != got {
|
||||||
expectedInputs := ""
|
expectedInputs := ""
|
||||||
missingInputs := ""
|
missingInputs := ""
|
||||||
|
@ -276,7 +278,7 @@ func getBindingsForFunc(fn reflect.Value, dependencies []*Dependency, paramsCoun
|
||||||
return bindings
|
return bindings
|
||||||
}
|
}
|
||||||
|
|
||||||
func getBindingsForStruct(v reflect.Value, dependencies []*Dependency, paramsCount int, sorter Sorter) (bindings []*binding) {
|
func getBindingsForStruct(v reflect.Value, dependencies []*Dependency, markExportedFieldsAsRequired bool, disablePayloadAutoBinding bool, paramsCount int, sorter Sorter) (bindings []*binding) {
|
||||||
typ := indirectType(v.Type())
|
typ := indirectType(v.Type())
|
||||||
if typ.Kind() != reflect.Struct {
|
if typ.Kind() != reflect.Struct {
|
||||||
panic("bindings: unresolved: no struct type")
|
panic("bindings: unresolved: no struct type")
|
||||||
|
@ -288,7 +290,7 @@ func getBindingsForStruct(v reflect.Value, dependencies []*Dependency, paramsCou
|
||||||
for _, f := range nonZero {
|
for _, f := range nonZero {
|
||||||
// fmt.Printf("Controller [%s] | NonZero | Field Index: %v | Field Type: %s\n", typ, f.Index, f.Type)
|
// fmt.Printf("Controller [%s] | NonZero | Field Index: %v | Field Type: %s\n", typ, f.Index, f.Type)
|
||||||
bindings = append(bindings, &binding{
|
bindings = append(bindings, &binding{
|
||||||
Dependency: NewDependency(elem.FieldByIndex(f.Index).Interface()),
|
Dependency: newDependency(elem.FieldByIndex(f.Index).Interface(), disablePayloadAutoBinding),
|
||||||
Input: newStructFieldInput(f),
|
Input: newStructFieldInput(f),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@ -308,13 +310,18 @@ func getBindingsForStruct(v reflect.Value, dependencies []*Dependency, paramsCou
|
||||||
inputs[i] = fields[i].Type
|
inputs[i] = fields[i].Type
|
||||||
}
|
}
|
||||||
|
|
||||||
exportedBindings := getBindingsFor(inputs, dependencies, paramsCount)
|
exportedBindings := getBindingsFor(inputs, dependencies, disablePayloadAutoBinding, paramsCount)
|
||||||
|
|
||||||
// fmt.Printf("Controller [%s] | Inputs length: %d vs Bindings length: %d | NonZero: %d | Stateless : %d\n",
|
// fmt.Printf("Controller [%s] | Inputs length: %d vs Bindings length: %d | NonZero: %d | Stateless : %d\n",
|
||||||
// typ, n, len(exportedBindings), len(nonZero), stateless)
|
// typ, n, len(exportedBindings), len(nonZero), stateless)
|
||||||
// for i, b := range exportedBindings {
|
// for i, b := range exportedBindings {
|
||||||
// fmt.Printf("[%d] [Static=%v] %#+v\n", i, b.Dependency.Static, b.Dependency.OriginalValue)
|
// fmt.Printf("[%d] [Static=%v] %#+v\n", i, b.Dependency.Static, b.Dependency.OriginalValue)
|
||||||
// }
|
// }
|
||||||
|
|
||||||
|
if markExportedFieldsAsRequired && len(exportedBindings) != n {
|
||||||
|
panic(fmt.Sprintf("MarkExportedFieldsAsRequired is true and at least one of struct's (%s) field was not binded to a dependency.\nFields length: %d, matched exported bindings length: %d.\nUse the Reporter for further details", typ.String(), n, len(exportedBindings)))
|
||||||
|
}
|
||||||
|
|
||||||
if stateless == 0 && len(nonZero) >= len(exportedBindings) {
|
if stateless == 0 && len(nonZero) >= len(exportedBindings) {
|
||||||
// if we have not a single stateless and fields are defined then just return.
|
// if we have not a single stateless and fields are defined then just return.
|
||||||
// Note(@kataras): this can accept further improvements.
|
// Note(@kataras): this can accept further improvements.
|
||||||
|
|
|
@ -269,7 +269,7 @@ func TestGetBindingsForFunc(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
for i, tt := range tests {
|
for i, tt := range tests {
|
||||||
bindings := getBindingsForFunc(reflect.ValueOf(tt.Func), c.Dependencies, 0)
|
bindings := getBindingsForFunc(reflect.ValueOf(tt.Func), c.Dependencies, c.DisablePayloadAutoBinding, 0)
|
||||||
|
|
||||||
if expected, got := len(tt.Expected), len(bindings); expected != got {
|
if expected, got := len(tt.Expected), len(bindings); expected != got {
|
||||||
t.Fatalf("[%d] expected bindings length to be: %d but got: %d of: %s", i, expected, got, bindings)
|
t.Fatalf("[%d] expected bindings length to be: %d but got: %d of: %s", i, expected, got, bindings)
|
||||||
|
@ -524,7 +524,7 @@ func TestBindingsForStruct(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
for i, tt := range tests {
|
for i, tt := range tests {
|
||||||
bindings := getBindingsForStruct(reflect.ValueOf(tt.Value), tt.Registered, 0, nil)
|
bindings := getBindingsForStruct(reflect.ValueOf(tt.Value), tt.Registered, false, false, 0, nil)
|
||||||
|
|
||||||
if expected, got := len(tt.Expected), len(bindings); expected != got {
|
if expected, got := len(tt.Expected), len(bindings); expected != got {
|
||||||
t.Logf("[%d] expected bindings length to be: %d but got: %d:\n", i, expected, got)
|
t.Logf("[%d] expected bindings length to be: %d but got: %d:\n", i, expected, got)
|
||||||
|
@ -546,3 +546,24 @@ func TestBindingsForStruct(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestBindingsForStructMarkExportedFieldsAsRequred(t *testing.T) {
|
||||||
|
type (
|
||||||
|
Embedded struct {
|
||||||
|
Val string
|
||||||
|
}
|
||||||
|
|
||||||
|
controller struct {
|
||||||
|
MyService service
|
||||||
|
Embedded *Embedded
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
dependencies := []*Dependency{
|
||||||
|
NewDependency(&Embedded{"test"}),
|
||||||
|
NewDependency(&serviceImpl{}),
|
||||||
|
}
|
||||||
|
|
||||||
|
// should panic if fail.
|
||||||
|
_ = getBindingsForStruct(reflect.ValueOf(new(controller)), dependencies, true, true, 0, nil)
|
||||||
|
}
|
||||||
|
|
|
@ -38,6 +38,21 @@ type Container struct {
|
||||||
Sorter Sorter
|
Sorter Sorter
|
||||||
// The dependencies entries.
|
// The dependencies entries.
|
||||||
Dependencies []*Dependency
|
Dependencies []*Dependency
|
||||||
|
|
||||||
|
// MarkExportedFieldsAsRequired reports whether all struct's fields
|
||||||
|
// MUST be binded to a dependency from the `Dependencies` list field.
|
||||||
|
// In-short, if it is set to true and if at least one exported field
|
||||||
|
// of a struct is not binded to a dependency then
|
||||||
|
// the entire application will exit with a panic message before server startup.
|
||||||
|
MarkExportedFieldsAsRequired bool
|
||||||
|
// DisablePayloadAutoBinding reports whether
|
||||||
|
// a function's parameter or struct's field of struct type
|
||||||
|
// should not be binded automatically to the request body (e.g. JSON)
|
||||||
|
// if a dependency for that type is missing.
|
||||||
|
// By default the binder will bind structs to request body,
|
||||||
|
// set to true to disable that kind of behavior.
|
||||||
|
DisablePayloadAutoBinding bool
|
||||||
|
|
||||||
// GetErrorHandler should return a valid `ErrorHandler` to handle bindings AND handler dispatch errors.
|
// GetErrorHandler should return a valid `ErrorHandler` to handle bindings AND handler dispatch errors.
|
||||||
// Defaults to a functon which returns the `DefaultErrorHandler`.
|
// Defaults to a functon which returns the `DefaultErrorHandler`.
|
||||||
GetErrorHandler func(*context.Context) ErrorHandler // cannot be nil.
|
GetErrorHandler func(*context.Context) ErrorHandler // cannot be nil.
|
||||||
|
@ -124,13 +139,13 @@ func (c *Container) fillReport(fullName string, bindings []*binding) {
|
||||||
// Contains the iris context, standard context, iris sessions and time dependencies.
|
// Contains the iris context, standard context, iris sessions and time dependencies.
|
||||||
var BuiltinDependencies = []*Dependency{
|
var BuiltinDependencies = []*Dependency{
|
||||||
// iris context dependency.
|
// iris context dependency.
|
||||||
NewDependency(func(ctx *context.Context) *context.Context { return ctx }).Explicitly(),
|
newDependency(func(ctx *context.Context) *context.Context { return ctx }, true).Explicitly(),
|
||||||
// standard context dependency.
|
// standard context dependency.
|
||||||
NewDependency(func(ctx *context.Context) stdContext.Context {
|
newDependency(func(ctx *context.Context) stdContext.Context {
|
||||||
return ctx.Request().Context()
|
return ctx.Request().Context()
|
||||||
}).Explicitly(),
|
}, true).Explicitly(),
|
||||||
// iris session dependency.
|
// iris session dependency.
|
||||||
NewDependency(func(ctx *context.Context) *sessions.Session {
|
newDependency(func(ctx *context.Context) *sessions.Session {
|
||||||
session := sessions.Get(ctx)
|
session := sessions.Get(ctx)
|
||||||
if session == nil {
|
if session == nil {
|
||||||
ctx.Application().Logger().Debugf("binding: session is nil\nMaybe inside HandleHTTPError? Register it with app.UseRouter(sess.Handler()) to fix it")
|
ctx.Application().Logger().Debugf("binding: session is nil\nMaybe inside HandleHTTPError? Register it with app.UseRouter(sess.Handler()) to fix it")
|
||||||
|
@ -141,52 +156,52 @@ var BuiltinDependencies = []*Dependency{
|
||||||
}
|
}
|
||||||
|
|
||||||
return session
|
return session
|
||||||
}).Explicitly(),
|
}, true).Explicitly(),
|
||||||
// application's logger.
|
// application's logger.
|
||||||
NewDependency(func(ctx *context.Context) *golog.Logger {
|
newDependency(func(ctx *context.Context) *golog.Logger {
|
||||||
return ctx.Application().Logger()
|
return ctx.Application().Logger()
|
||||||
}).Explicitly(),
|
}, true).Explicitly(),
|
||||||
// time.Time to time.Now dependency.
|
// time.Time to time.Now dependency.
|
||||||
NewDependency(func(ctx *context.Context) time.Time {
|
newDependency(func(ctx *context.Context) time.Time {
|
||||||
return time.Now()
|
return time.Now()
|
||||||
}).Explicitly(),
|
}, true).Explicitly(),
|
||||||
// standard http Request dependency.
|
// standard http Request dependency.
|
||||||
NewDependency(func(ctx *context.Context) *http.Request {
|
newDependency(func(ctx *context.Context) *http.Request {
|
||||||
return ctx.Request()
|
return ctx.Request()
|
||||||
}).Explicitly(),
|
}, true).Explicitly(),
|
||||||
// standard http ResponseWriter dependency.
|
// standard http ResponseWriter dependency.
|
||||||
NewDependency(func(ctx *context.Context) http.ResponseWriter {
|
newDependency(func(ctx *context.Context) http.ResponseWriter {
|
||||||
return ctx.ResponseWriter()
|
return ctx.ResponseWriter()
|
||||||
}).Explicitly(),
|
}, true).Explicitly(),
|
||||||
// http headers dependency.
|
// http headers dependency.
|
||||||
NewDependency(func(ctx *context.Context) http.Header {
|
newDependency(func(ctx *context.Context) http.Header {
|
||||||
return ctx.Request().Header
|
return ctx.Request().Header
|
||||||
}).Explicitly(),
|
}, true).Explicitly(),
|
||||||
// Client IP.
|
// Client IP.
|
||||||
NewDependency(func(ctx *context.Context) net.IP {
|
newDependency(func(ctx *context.Context) net.IP {
|
||||||
return net.ParseIP(ctx.RemoteAddr())
|
return net.ParseIP(ctx.RemoteAddr())
|
||||||
}).Explicitly(),
|
}, true).Explicitly(),
|
||||||
// Status Code (special type for MVC HTTP Error handler to not conflict with path parameters)
|
// Status Code (special type for MVC HTTP Error handler to not conflict with path parameters)
|
||||||
NewDependency(func(ctx *context.Context) Code {
|
newDependency(func(ctx *context.Context) Code {
|
||||||
return Code(ctx.GetStatusCode())
|
return Code(ctx.GetStatusCode())
|
||||||
}).Explicitly(),
|
}, true).Explicitly(),
|
||||||
// Context Error. May be nil
|
// Context Error. May be nil
|
||||||
NewDependency(func(ctx *context.Context) Err {
|
newDependency(func(ctx *context.Context) Err {
|
||||||
err := ctx.GetErr()
|
err := ctx.GetErr()
|
||||||
if err == nil {
|
if err == nil {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
return err
|
return err
|
||||||
}).Explicitly(),
|
}, true).Explicitly(),
|
||||||
// Context User, e.g. from basic authentication.
|
// Context User, e.g. from basic authentication.
|
||||||
NewDependency(func(ctx *context.Context) context.User {
|
newDependency(func(ctx *context.Context) context.User {
|
||||||
u := ctx.User()
|
u := ctx.User()
|
||||||
if u == nil {
|
if u == nil {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
return u
|
return u
|
||||||
}),
|
}, true),
|
||||||
// payload and param bindings are dynamically allocated and declared at the end of the `binding` source file.
|
// payload and param bindings are dynamically allocated and declared at the end of the `binding` source file.
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -228,6 +243,8 @@ func (c *Container) Clone() *Container {
|
||||||
clonedDeps := make([]*Dependency, len(c.Dependencies))
|
clonedDeps := make([]*Dependency, len(c.Dependencies))
|
||||||
copy(clonedDeps, c.Dependencies)
|
copy(clonedDeps, c.Dependencies)
|
||||||
cloned.Dependencies = clonedDeps
|
cloned.Dependencies = clonedDeps
|
||||||
|
cloned.DisablePayloadAutoBinding = c.DisablePayloadAutoBinding
|
||||||
|
cloned.MarkExportedFieldsAsRequired = c.MarkExportedFieldsAsRequired
|
||||||
cloned.resultHandlers = c.resultHandlers
|
cloned.resultHandlers = c.resultHandlers
|
||||||
// Reports are not cloned.
|
// Reports are not cloned.
|
||||||
return cloned
|
return cloned
|
||||||
|
@ -264,7 +281,7 @@ func Register(dependency interface{}) *Dependency {
|
||||||
// - Register(func(ctx iris.Context) User {...})
|
// - Register(func(ctx iris.Context) User {...})
|
||||||
// - Register(func(User) OtherResponse {...})
|
// - Register(func(User) OtherResponse {...})
|
||||||
func (c *Container) Register(dependency interface{}) *Dependency {
|
func (c *Container) Register(dependency interface{}) *Dependency {
|
||||||
d := NewDependency(dependency, c.Dependencies...)
|
d := newDependency(dependency, c.DisablePayloadAutoBinding, c.Dependencies...)
|
||||||
if d.DestType == nil {
|
if d.DestType == nil {
|
||||||
// prepend the dynamic dependency so it will be tried at the end
|
// prepend the dynamic dependency so it will be tried at the end
|
||||||
// (we don't care about performance here, design-time)
|
// (we don't care about performance here, design-time)
|
||||||
|
|
|
@ -51,6 +51,10 @@ func (d *Dependency) String() string {
|
||||||
//
|
//
|
||||||
// See `Container.Handler` for more.
|
// See `Container.Handler` for more.
|
||||||
func NewDependency(dependency interface{}, funcDependencies ...*Dependency) *Dependency {
|
func NewDependency(dependency interface{}, funcDependencies ...*Dependency) *Dependency {
|
||||||
|
return newDependency(dependency, false, funcDependencies...)
|
||||||
|
}
|
||||||
|
|
||||||
|
func newDependency(dependency interface{}, disablePayloadAutoBinding bool, funcDependencies ...*Dependency) *Dependency {
|
||||||
if dependency == nil {
|
if dependency == nil {
|
||||||
panic(fmt.Sprintf("bad value: nil: %T", dependency))
|
panic(fmt.Sprintf("bad value: nil: %T", dependency))
|
||||||
}
|
}
|
||||||
|
@ -70,7 +74,7 @@ func NewDependency(dependency interface{}, funcDependencies ...*Dependency) *Dep
|
||||||
OriginalValue: dependency,
|
OriginalValue: dependency,
|
||||||
}
|
}
|
||||||
|
|
||||||
if !resolveDependency(v, dest, funcDependencies...) {
|
if !resolveDependency(v, disablePayloadAutoBinding, dest, funcDependencies...) {
|
||||||
panic(fmt.Sprintf("bad value: could not resolve a dependency from: %#+v", dependency))
|
panic(fmt.Sprintf("bad value: could not resolve a dependency from: %#+v", dependency))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -80,11 +84,11 @@ func NewDependency(dependency interface{}, funcDependencies ...*Dependency) *Dep
|
||||||
// DependencyResolver func(v reflect.Value, dest *Dependency) bool
|
// DependencyResolver func(v reflect.Value, dest *Dependency) bool
|
||||||
// Resolver DependencyResolver
|
// Resolver DependencyResolver
|
||||||
|
|
||||||
func resolveDependency(v reflect.Value, dest *Dependency, funcDependencies ...*Dependency) bool {
|
func resolveDependency(v reflect.Value, disablePayloadAutoBinding bool, dest *Dependency, funcDependencies ...*Dependency) bool {
|
||||||
return fromDependencyHandler(v, dest) ||
|
return fromDependencyHandler(v, dest) ||
|
||||||
fromStructValue(v, dest) ||
|
fromStructValue(v, dest) ||
|
||||||
fromFunc(v, dest) ||
|
fromFunc(v, dest) ||
|
||||||
len(funcDependencies) > 0 && fromDependentFunc(v, dest, funcDependencies)
|
len(funcDependencies) > 0 && fromDependentFunc(v, disablePayloadAutoBinding, dest, funcDependencies)
|
||||||
}
|
}
|
||||||
|
|
||||||
func fromDependencyHandler(_ reflect.Value, dest *Dependency) bool {
|
func fromDependencyHandler(_ reflect.Value, dest *Dependency) bool {
|
||||||
|
@ -197,7 +201,7 @@ func handlerFromFunc(v reflect.Value, typ reflect.Type) DependencyHandler {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func fromDependentFunc(v reflect.Value, dest *Dependency, funcDependencies []*Dependency) bool {
|
func fromDependentFunc(v reflect.Value, disablePayloadAutoBinding bool, dest *Dependency, funcDependencies []*Dependency) bool {
|
||||||
// * func(<D>...) returns <T>
|
// * func(<D>...) returns <T>
|
||||||
// * func(<D>...) returns error
|
// * func(<D>...) returns error
|
||||||
// * func(<D>...) returns <T>, error
|
// * func(<D>...) returns <T>, error
|
||||||
|
@ -207,7 +211,7 @@ func fromDependentFunc(v reflect.Value, dest *Dependency, funcDependencies []*De
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
bindings := getBindingsForFunc(v, funcDependencies, -1 /* parameter bindings are disabled for depent dependencies */)
|
bindings := getBindingsForFunc(v, funcDependencies, disablePayloadAutoBinding, -1 /* parameter bindings are disabled for depent dependencies */)
|
||||||
|
|
||||||
numIn := typ.NumIn()
|
numIn := typ.NumIn()
|
||||||
numOut := typ.NumOut()
|
numOut := typ.NumOut()
|
||||||
|
|
|
@ -107,7 +107,7 @@ func makeHandler(fn interface{}, c *Container, paramsCount int) context.Handler
|
||||||
typ := v.Type()
|
typ := v.Type()
|
||||||
numIn := typ.NumIn()
|
numIn := typ.NumIn()
|
||||||
|
|
||||||
bindings := getBindingsForFunc(v, c.Dependencies, paramsCount)
|
bindings := getBindingsForFunc(v, c.Dependencies, c.DisablePayloadAutoBinding, paramsCount)
|
||||||
c.fillReport(context.HandlerName(fn), bindings)
|
c.fillReport(context.HandlerName(fn), bindings)
|
||||||
|
|
||||||
resultHandler := defaultResultHandler
|
resultHandler := defaultResultHandler
|
||||||
|
|
|
@ -51,7 +51,7 @@ func makeStruct(structPtr interface{}, c *Container, partyParamsCount int) *Stru
|
||||||
}
|
}
|
||||||
|
|
||||||
// get struct's fields bindings.
|
// get struct's fields bindings.
|
||||||
bindings := getBindingsForStruct(v, c.Dependencies, partyParamsCount, c.Sorter)
|
bindings := getBindingsForStruct(v, c.Dependencies, c.MarkExportedFieldsAsRequired, c.DisablePayloadAutoBinding, partyParamsCount, c.Sorter)
|
||||||
|
|
||||||
// length bindings of 0, means that it has no fields or all mapped deps are static.
|
// length bindings of 0, means that it has no fields or all mapped deps are static.
|
||||||
// If static then Struct.Acquire will return the same "value" instance, otherwise it will create a new one.
|
// If static then Struct.Acquire will return the same "value" instance, otherwise it will create a new one.
|
||||||
|
|
Loading…
Reference in New Issue
Block a user