Feature request: Scope-private bindings
See original GitHub issueSome bindings are meant to be injected only in the scope in which they are defined, such that injecting them in a subscope is a logical bug. For example, let’s say that I add a Closer
binding to my application scope to allow objects to register for cleanup. If an object belonging to a strict subscope of the application scope were to use this Closer
, it would get leaked until application cleanup. In the Android world, a Lifecycle
object in an activity scope would cause objects in strict subscopes to leak until activity destruction if they were to add themselves as observers.
I’ve seen this issue numerous times with objects that are essentially event dispatchers: release notifiers, lifecycle event dispatchers, save state handlers… We typically deal with them by qualifying them with a @WithMatchingScope(SCOPE_NAME)
annotation, and using static analysis to detect injection in the wrong scopes. However, this is just adding extra boilerplate to work around the core problem: the binding should just not be visible at all outside of the scope for which it’s intended. It would be ideal if Dagger allowed annotating such bindings with a marker such as @Private
and enforced the contract.
One nice side effect of using scope-private bindings is that nested subcomponents would be able to declare their own instances of each binding without the extra qualification. For example, I’d like to be able to add Closers
to all my scopes without concern for clashes, since each Closer
is meant to be used only within its own scope. And, more importantly, I’d be able to use Closer
without the extra qualification in the injected constructor of my unscoped objects, and get the right instance of the Closer
based on the instantiation scope. This would be a critical piece of an implementation of a generic component cleanup mechanism in Dagger.
Issue Analytics
- State:
- Created 5 years ago
- Reactions:1
- Comments:7 (2 by maintainers)
Top GitHub Comments
I think that this kind of feature would be particularly useful on Android, since it uses very strict lifecycles in multiple nested scopes, but has general value in any applications that implement a concept of lifecycle or component-scoped event dispatcher.
The alternatives that you suggest are workable, but they require central coordination. Also, they don’t prevent registration of an object in a
Closer
(or other type of event dispatcher) in the wrong scope. Also, it couples component definitions to specific scopes. For example let’s say that I define this:Ideally, I’d like to be able to inject
MyViewController
in any scope, and let dagger figure out withLifecycle
is available within that particular scope. Using a qualifier like, say,@FeatureXScope
would tie this component to that scope and hinder reuse.In the case of unscoped bindings, I would think that every unscoped injection can ultimately be traced back to a particular component. You’re likely already doing that to determine which scoped bindings are available for injection into an unscoped binding, right?
It would seem there is other “high impact” projects leaning heavily on the concept of a scope local or override mechanism.
https://developer.android.com/jetpack/compose/compositionlocal