Skip to content

[AssistedInject] Allow scoping of AssistedFactory with annotations #2974

Open
@ferinagy

Description

@ferinagy

Dagger version: 2.40
Sample project: https://github.com/ghus-raba/dagger-assisted-sample

Currently, annotating an assisted factory with scope like @Singleton takes no effect and the factory can inject also dependencies from other scopes.

In the sample project there is an AppComponent with @Singleton scope and it has a subcomponent ActivityComponent with @ActivityScope. We try to inject dependencies to ViewModel and try to ensure that only unscoped or @Singleton scoped dependencies can be injected, as its lifecycle is longer that the one of Activity.

When we do assisted injection manually, we can annotate the factory as @Singleton and it will correctly be provided by AppComponent. Trying to inject a dependency from @ActivityScope results in compilation error with [Dagger/IncompatiblyScopedBindings]:

class ManuallyAssistedViewModel constructor(
    foo: Foo,
    bar: Bar,
    assisted: Int
) : ViewModel() {

    @Singleton
    class Factory @Inject constructor(
        val fooProvider: Provider<Foo>,
        val barProvider: Provider<Bar>,
    ) {
        fun create(assisted: Int) = ManuallyAssistedViewModel(
            fooProvider.get(),
            barProvider.get(),
            assisted
        )
    }

}

However, if we do the same with @AssistedFactory, the @Singleton annotation is ignored and an Activity instance is injected.

class AssistedViewModel @AssistedInject constructor(
    foo: Foo,
    bar: Bar,
    activity: Activity,
    @Assisted assisted: Int
) : ViewModel() {

    @Singleton // this does nothing
    @AssistedFactory
    interface Factory {
        fun create(assisted: Int): AssistedViewModel
    }
}

Both of the above factories are injected in an activity like this:

private lateinit var component: ActivityComponent

@Inject internal lateinit var manuallyAssistedViewModelFactory: ManuallyAssistedViewModel.Factory
@Inject internal lateinit var assistedViewModelFactory: AssistedViewModel.Factory

override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    component = application.component.activityComponentFactory.build(this)
    component.inject(this)

    // ...
}

We can explicitly provide the AssistedViewModel.Factory from AppComponent by adding a provision method val assistedFactory: AssistedViewModel.Factory, even if we do not use it and keep the injection as shown above.

It would be nice, if we could just use a scope annotation the same way as it is possible with manual way.

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions