I am attempting to upgrade from Dagger 2.7 to Dagger 2.21 in an Android app. So far, that has mostly involved adding new scopes to subcomponents, as this is enforced in Dagger 2.8+, but wasn't in Dagger 2.7. I have been stuck for a few hours on an error that I was hoping someone could help me get past. The error is this:
error: [Dagger/MissingBinding] com.experticity.android.member.model.card.survey.SurveyCampaign cannot be provided without an @Inject constructor or an @Provides-annotated method.
I have an @Provides
method in a module though:
@Module
class SurveyPlayerModule(private val surveyCampaign: SurveyCampaign) {
@Provides
@FragmentScope
fun provideSurveyCampaign(): SurveyCampaign {
return surveyCampaign
}
}
And I provide that surveyCampaign from my fragment:
getComponent().surveyPlayerFragmentComponent(
new SurveyPlayerModule(mSurveyCampaign), new FragmentModule(this));
The class that doesn’t seem to be able to get the survey campaign is the SurveyTracker
and the constructor looks like this:
@Inject
public SurveyTracker(UserRepository userRepository, CampaignRepository campaignRepository, SurveyCampaign surveyCampaign) {// Set all of the fields from the constructor parameters}
And yes, our project is a mix of Kotlin and Java, moving gradually towards more and more Kotlin.
And the rest of the error message, with package names removed for brevity:
SurveyCampaign is injected at SurveyTracker(…, surveyCampaign)
SurveyTracker is provided at SurveyPlayerFragmentComponent.surveyTracker() [ApplicationComponent → SessionComponent → RepositoryComponent → activity.ActivityComponent → activity.SurveyPlayerFragmentComponent]
The following other entry points also depend on it:
SurveyPlayerFragmentComponent.inject(SurveyPlayerViewModel) [ApplicationComponent → SessionComponent → RepositoryComponent → activity.ActivityComponent → activity.SurveyPlayerFragmentComponent]
SurveyPlayerFragmentComponent.inject(SurveyQuestionViewModel) [ApplicationComponent → SessionComponent → RepositoryComponent → activity.ActivityComponent → activity.SurveyPlayerFragmentComponent]
SurveyPlayerFragmentComponent.inject(SurveyCompletedViewModel) [ApplicationComponent → SessionComponent → RepositoryComponent → activity.ActivityComponent → activity.SurveyPlayerFragmentComponent]
The full, un-edited error stack:
ApplicationComponent.java:11: error: [Dagger/MissingBinding] com.experticity.android.member.model.card.survey.SurveyCampaign cannot be provided without an @Inject constructor or an @Provides-annotated method.
public abstract interface ApplicationComponent {
^
com.experticity.android.member.model.card.survey.SurveyCampaign is injected at
com.experticity.android.member.domain.SurveyTracker(…, surveyCampaign)
com.experticity.android.member.domain.SurveyTracker is injected at
com.experticity.android.member.ui.viewmodel.SurveyPlayerViewModel.mSurveyTracker
com.experticity.android.member.ui.viewmodel.SurveyPlayerViewModel is injected at
com.experticity.android.member.injection.component.activity.SurveyPlayerFragmentComponent.inject(com.experticity.android.member.ui.viewmodel.SurveyPlayerViewModel) [com.experticity.android.member.injection.component.ApplicationComponent → com.experticity.android.member.injection.component.SessionComponent → com.experticity.android.member.injection.component.RepositoryComponent → com.experticity.android.member.injection.component.activity.ActivityComponent → com.experticity.android.member.injection.component.activity.SurveyPlayerFragmentComponent]
The following other entry points also depend on it:
com.experticity.android.member.injection.component.activity.SurveyPlayerFragmentComponent.inject(com.experticity.android.member.ui.viewmodel.SurveyQuestionViewModel) [com.experticity.android.member.injection.component.ApplicationComponent → com.experticity.android.member.injection.component.SessionComponent → com.experticity.android.member.injection.component.RepositoryComponent → com.experticity.android.member.injection.component.activity.ActivityComponent → com.experticity.android.member.injection.component.activity.SurveyPlayerFragmentComponent]
com.experticity.android.member.injection.component.activity.SurveyPlayerFragmentComponent.inject(com.experticity.android.member.ui.viewmodel.SurveyCompletedViewModel) [com.experticity.android.member.injection.component.ApplicationComponent → com.experticity.android.member.injection.component.SessionComponent → com.experticity.android.member.injection.component.RepositoryComponent → com.experticity.android.member.injection.component.activity.ActivityComponent → com.experticity.android.member.injection.component.activity.SurveyPlayerFragmentComponent]
And here is the component:
@FragmentScope
@Subcomponent(modules = [SurveyPlayerModule::class, FragmentModule::class])
interface SurveyPlayerFragmentComponent {
@ChildFragmentManager
fun childFragmentManager(): FragmentManager
fun surveyTracker(): SurveyTracker
//Fragments
fun inject(fragment: SurveyPlayerFragment)
// ViewModels
fun inject(viewModel: SurveyPlayerViewModel)
fun inject(viewModel: SurveyQuestionViewModel)
fun inject(viewModel: SurveyCompletedViewModel)
// Adapters
fun inject(adapter: SurveyPlayerAdapter)
}