** Use to override definitions of an IoC service.
**
** pre>
** syntax: fantom
** overrideBuilder := regBuilder.overrideService("acme::Sheep")
** overrideBuilder
** .withImplType(WolfImpl#)
** .withCtorVals(["teeth"])
** .withScope("root")
** <pre
@Js
mixin ServiceOverrideBuilder {
** Overrides the service implementation.
abstract This withImplType(Type? implType)
** Overrides service aliases with the given ID.
abstract This withAlias(Str alias)
** Overrides service aliases with the given list.
abstract This withAliases(Str[]? aliases)
** Overrides service alias types with the given type.
abstract This withAliasType(Type aliasType)
** Overrides service alias types with the given list.
abstract This withAliasTypes(Type[]? aliasTypes)
** Overrides service scopes with the given scope ID.
abstract This withScope(Str scope)
** Overrides service scopes with the given scope list.
abstract This withScopes(Str[]? scopes)
** Overrides the service builder func.
abstract This withBuilder(|Scope -> Obj?|? serviceBuilder)
** Overrides the service ctor args.
abstract This withCtorArgs(Obj?[]? args)
** Overrides the service field vals.
abstract This withFieldVals([Field:Obj?]? fieldVals)
** Marks this override as *optional*. That is, should the service you're attempting to override
** not exist, no errors are thrown and this override is silently ignored.
**
** Useful for overriding 3rd party libraries that may not be part of the current project.
abstract This optional(Bool optional := true)
** Sets an override ID so others may override this override.
**
** pre>
** syntax: fantom
** // override the sheep service
** regBuilder.overrideService("acme::Sheep").withOverrideId("wolf").withImplType(WolfImpl#)
**
** // override the wolf override
** regBuilder.overrideService("wolf").withOverrideId("bear").withImplType(BearImpl#)
**
** // override the bear override
** regBuilder.overrideService("bear").withOverrideId("frog").withImplType(FrogImpl#)
**
** <pre
abstract This withOverrideId(Str overrideId)
}
@Js
internal class ServiceOverrideBuilderImpl : ServiceOverrideBuilder {
internal OvrDef ovrDef
internal new make(Type moduleId) {
this.ovrDef = OvrDef {
it.moduleId = moduleId
}
}
override This withImplType(Type? serviceImplType) {
if (serviceImplType != null && serviceImplType.isMixin)
throw ArgErr(ErrMsgs.autobuilder_bindImplNotClass(serviceImplType))
ovrDef.implType = serviceImplType
if (serviceImplType != null) {
ovrDef.autobuild = true
ovrDef.builder = null
if (ovrDef.overrideId == null)
ovrDef.overrideId = serviceImplType.qname
} else
ovrDef.autobuild = false
return this
}
override This withAlias(Str alias) {
ovrDef.aliases = Str[alias]
return this
}
override This withAliases(Str[]? aliases) {
ovrDef.aliases = aliases
return this
}
override This withAliasType(Type aliasType) {
ovrDef.aliasTypes = [aliasType]
return this
}
override This withAliasTypes(Type[]? aliasTypes) {
ovrDef.aliasTypes = aliasTypes
return this
}
override This withScope(Str serviceScope) {
withScopes([serviceScope])
}
override This withScopes(Str[]? serviceScopes) {
ovrDef.scopes = toImmutableObj(serviceScopes)
return this
}
override This withBuilder(|Scope -> Obj?|? serviceBuilder) {
ovrDef.builder = toImmutableObj(serviceBuilder)
if (serviceBuilder != null) {
ovrDef.autobuild = false
ovrDef.implType = null
} else
ovrDef.autobuild = true
return this
}
** Passed as args to the service ctor. The args must be immutable.
override This withCtorArgs(Obj?[]? args) {
ovrDef.ctorArgs = toImmutableObj(args)
if (args != null) // if null, we may not be autobuilding
ovrDef.autobuild = true
return this
}
** Field values to set in the service impl. An alternative to using ctor args. All vals must be immutable.
override This withFieldVals([Field:Obj?]? fieldVals) {
ovrDef.fieldVals = toImmutableObj(fieldVals)
if (fieldVals != null) // if null, we may not be autobuilding
ovrDef.autobuild = true
return this
}
override This optional(Bool optional := true) {
ovrDef.optional = optional
return this
}
override This withOverrideId(Str overrideId) {
ovrDef.overrideId = overrideId
return this
}
private Obj? toImmutableObj(Obj? obj) {
if (obj is Func)
return Env.cur.runtime == "js" ? obj : obj.toImmutable
return obj?.toImmutable
}
}