Dagger2 incomplete Component dependencies

I’m fairly new to Dagger2 and i’m having some trouble using it.

So let’s say I have four project modules (app, data and domain)

  • domain has the business logic (interactors for app to use) and some interfaces for data to implement

  • app is supposed to do the wiring so it should provide domain with the interface implementation provided by data and it should receive the interactors from it

I want to do said wiring without exposing the internal graph of any of these modules, for example:

  • If the data module implements a Repository interface provided by domain and it uses internally a CloudRepository and a LocalRepository to create it, I don’t want other project modules to know these two repositories exist, they should only know of the Repository implementation:
/* domain */

interface Interactor
interface Repository
class InteractorImpl(repository: Repository): Interactor


/* data */

interface LocalRepository
class LocalRepositoryImpl : LocalRepository

interface CloudRepository
class CloudRepositoryImpl : CloudRepository

class RepositoryImpl(local: LocalRepository, cloud: CloudRepository) : Repository

My initial thoughts were to use Component dependencies, so I created a Component for each project module that only exposes what I need it to (only RepositoryImplDaggerModule for data and interactors dagger modules for domain) and the app component would depend on them:

/* domain */

@Module
class InteractorModule {
    @Provides
    fun provideInteractor(repository: Repository): Interactor = InteractorImpl(repository)
}

@Module
class FilterModule {
    @Provides
    fun provideFilter(): Filter = FilterImpl()
}

@Component(modules = [InteractorModule::class, FilterModule::class])
class DomainComponent {
    fun interactor: Interactor //only expose this
}

/* data */

@Module
class LocalRepositoryModule {
    @Provides
    fun provideLocalRepository(): LocalRepository = LocalRepositoryImpl()
}

@Module
class CloudRepositoryModule {
    @Provides
    fun provideCloudRepository(): CloudRepository = CloudRepositoryImpl()
}

@Module
class RepositoryModule {
    @Provides
    fun provideRepository(local: LocalRepository, cloud: CloudRepository): Repository = RepositoryImpl(local, cloud)
}

//should be able to depend on DomainComponent if needed
@Component(modules = [LocalRepositoryModule::class, CloudRepositoryModule::class, RepositoryModule::class])
class DataComponent {
    fun repository: Repository //only expose this
}

/* app */

@Component(dependencies = [DomainComponent::class, DataComponent::class])
class AppComponent 

Which looked perfect at first glance, but when I click build I get an error because DomainComponent isincomplete (it needs to know about theRepository` implementation), Dagger2 wouldn’t allow me to
create incomplete components.

Some SO suggestions on kinda similar problems were to use Subcomponents but they expose their entire graph and I don’t think they can provide their parent Component with dependencies (providing app with interactors in this case).

Other suggestions were to replace DomainComponent and DataComponent with Modules and use inculdes, but then again, they expose their entire graph of included Modules.

So i’m kinda stuck here, I want the lower layers of my application (data and domain) to exchange dependencies through the app component while providing the app component with interactors and also keeping their internal graph hidden.

Thank you!

Leave a Reply

avatar
  Subscribe  
Notify of