5

In my application, I have two modules: app and repository.
repository depends on Room, and has a GoalRepository interface:

interface GoalRepository

and a GoalRepositoryImpl class that is internal, as I don't want to expose it or the Room dependency to other modules:

@Singleton
internal class GoalRepositoryImpl @Inject constructor(private val dao: GoalDao) : GoalRepository

app depends on repository to get a GoalRepository instance.
I have a GoalRepositoryModule that, at the moment, is:

@Module
class GoalRepositoryModule {
    @Provides
    @Singleton
    fun provideRepository(impl: GoalRepositoryImpl): GoalRepository = impl

    @Provides
    @Singleton
    internal fun provideGoalDao(appDatabase: AppDatabase): GoalDao = appDatabase.goalDao()

    @Provides
    @Singleton
    internal fun provideDatabase(context: Context): AppDatabase =
        Room.databaseBuilder(context, AppDatabase::class.java, "inprogress-db").build()
}

The issue is that this won't compile (obviously) as the public provideRepository function is exposing GoalRepositoryImpl, that is an internal class.
How can I structure my Dagger setup to achieve what I want?


Edit:
I tried making provideRepository internal as per @David Medenjak comment and now the Kotlin compiler complains that it cannot resolve RoomDatabase dependency:

Supertypes of the following classes cannot be resolved. Please make sure you have the required dependencies in the classpath:
    class xxx.repository.database.AppDatabase, unresolved supertypes: androidx.room.RoomDatabase    

For completeness, the code of my Component inside the app module:

@Component(modules = [ContextModule::class, GoalRepositoryModule::class])
@Singleton
interface SingletonComponent
gpunto
  • 2,573
  • 1
  • 14
  • 17
  • Why can't you make `provideRepository` internal as well? Just tried it, seems to work fine, especially since Dagger generates java code and internal is still "public" in Java – David Medenjak May 11 '19 at 13:06
  • I tried your suggestion, now the Kotlin compiler complains about a missing dependency. I've updated my question – gpunto May 11 '19 at 13:15

1 Answers1

1

After looking at the code Dagger was generating, I understood that the mistake was making the @Component inside the app module depend on the @Module inside the repository module.
So I made a separate @Component inside the repository module and made the app module's one depend on it.

The code

The repository module's component:

@Component(modules = [GoalRepositoryModule::class])
interface RepositoryComponent {
    fun goalRepository(): GoalRepository
}

The app's one:

@Component(modules = [ContextModule::class], dependencies = [RepositoryComponent::class])
@Singleton
interface SingletonComponent

This way the RepositoryComponent is responsible for building the Repository and knows all its dependencies, while the SingletonComponent only have to know about RepositoryComponent.

gpunto
  • 2,573
  • 1
  • 14
  • 17
  • Can you provide the project's GitHub link? As I am trying to implement dagger 2 in a multi-module android project. – sagar suri Oct 14 '19 at 13:11
  • I'm in a similar situation, and one think that makes me doubt is (I'm new to Dagger) .. that RepositoryComponent and the repository module itself, need Context to work, but that "dependence" is hidden so someone else will become aware of this when they compile the project and an error gets thrown. Is this a usual thing when using Dagger ? – Nicolás Vera Dec 21 '19 at 04:13