Search code examples
androiddagger-2dagger

Dagger2 not finding provided instance


I'm facing some issues trying to use Dagger with multiple Components, I have the following (each class is in its own file):

Scopes:

@Scope
@Retention(AnnotationRetention.RUNTIME)
annotation class PrototypeScope

Modules:

@Module(includes = [RepositoriesModule::class])
class GetRandomBookUseCaseModule {

    @Provides
    @Singleton
    fun provideGetRandomBookUseCase(booksRepository: BooksRepository) =
        GetRandomBookUseCase(booksRepository)
}


@Module
class RepositoriesModule {

    @Provides
    @Singleton
    fun providesBooksRepository(): BooksRepository = BooksRepositoryImpl()

    @Provides
    @Singleton
    fun providesPreferencesRepository(): PreferencesRepository = PreferencesRepositoryImpl()
}


@Module
class BookReaderModule(val ctx: Context) {

    @Provides
    @PrototypeScope
    fun provideBookReader(getRandomBookUseCase: GetRandomBookUseCase) =
        BookReader(ctx, getRandomBookUseCase)
}

Components:

@Component(
    modules = [GetRandomBookUseCaseModule::class]
)
interface UseCasesComponent {

}

@Component(
    dependencies = [UseCasesComponent::class],
    modules = [BookReaderModule::class]
)
@PrototypeScope
interface BookReaderFragmentComponent {

    fun inject(bookReaderFragment: BookReaderFragment)
}

Then, in BookReaderFragment I have the following:

class BookReaderFragment : Fragment() {
    @Inject lateinit var bookReader: BookReader
    val component: BookReaderFragmentComponent by lazy {
        DaggerBookReaderFragmentComponent
            .builder()
            .useCasesComponent(DaggerUseCasesComponent.create())
            .bookReaderModule(BookReaderModule(context!!))
            .build()
    }

    override fun onActivityCreated(savedInstanceState: Bundle?) {
        super.onActivityCreated(savedInstanceState)
        component.inject(this)
        ...
    }

    ...
}

However, Dagger is failing ought to:

error: GetRandomBookUseCase cannot be provided without an @Inject constructor or an @Provides-annotated method.

What is going on? Why Dagger is not finding the provided method?

Thanks a lot

UPDATE: Adding RepositoriesModule as included in GetRandomBookUseCaseModule. After this change, I have realised that, although the error message, the issue is related with the way the BookReader is injected. If I remove the @Injected from the BookReaderFragment this way:

class BookReaderFragment : Fragment() {
    lateinit var bookReader: BookReader
    val component: BookReaderFragmentComponent by lazy {
        DaggerBookReaderFragmentComponent
            .builder()
            .useCasesComponent(DaggerUseCasesComponent.create())
            .bookReaderModule(BookReaderModule(context!!))
            .build()
    }

    override fun onActivityCreated(savedInstanceState: Bundle?) {
        super.onActivityCreated(savedInstanceState)
        component.inject(this)
        ...
    }

    ...
}

Then there's no error, however it will not work on runtime, but when the @Inject is set, then the error is thrown.


Solution

  • Include RepositoriesModule into GetRandomBookUseCaseModule

    @Module(includes = {RepositoriesModule.class})
    class {
    
        @Provides
        @Singleton
        fun provideGetRandomBookUseCase(booksRepository: BooksRepository) =
            GetRandomBookUseCase(booksRepository)
    }
    

    And Component should be

    @Component(
        modules = [GetRandomBookUseCaseModule::class]
    )
    interface UseCasesComponent {
        GetRandomBookUseCase getRandomBookUseCase();
    }