How to define Entry point for multiple implementation of interface using Hilt custom component?

1.3k Views Asked by At

I have created a custom component AuthUserComponent using Hilt and need to provide multiple implementation to DataRepository interface.

class Sample @Inject constructor(
    @DemoMode private val demoRepository: DataRepository,
    @ProductionMode private val productionRepository: DataRepository
) {}

I have created the below @Provides implementations of the interface:

Module
@InstallIn(AuthUserComponent::class)
object DIModule {

    @AuthUserScope
    @DemoMode
    @Provides
    fun provideDataRepositoryImplDemo(): DataRepository =
        DataRepositoryImplDemo()

    @AuthUserScope
    @Provides
    @ProductionMode
    fun provideDataRepositoryImpl(): DataRepository =
        DataRepositoryImpl()
}

How do I provide multiple repository implementations via Entrypoint and bridge it with SingletonComponent? I get the below error:

DataRepository is bound multiple times error

@InstallIn(AuthUserComponent::class)
@EntryPoint
 interface AuthUserDataEntryPoint {
    @ProductionMode
    fun dataRepositoryImpl(): DataRepository 
    @DemoMode
    fun dataRepositoryImplDemo(): DataRepository 
}

@Module
@InstallIn(SingletonComponent::class)
internal object AuthUserDataEntryBridge {
    @DemoMode
    @Provides
    internal fun provideDataRepositoryImplDemo(
        authUserComponentManager: AuthUserComponentManager
    ): DataRepository {
        return EntryPoints
            .get(authUserComponentManager, AuthUserDataEntryPoint::class.java)
            .dataRepositoryImplDemo()
    }

    @ProductionMode
    @Provides
    internal fun provideDataRepositoryImpl(
        authUserComponentManager: AuthUserComponentManager
    ): DataRepository {
        return EntryPoints
            .get(authUserComponentManager, AuthUserDataEntryPoint::class.java)
            .dataRepositoryImpl()
    }
}


1

There are 1 best solutions below

0
Brian Yencho On

The issue to me seems to be that you are defining implementations in both DIModule and AuthUserDataEntryBridge for the same things. To be honest, I'm not really sure what the purpose of AuthUserDataEntryBridge is and I'm unfamiliar with the usage of EntryPoints inside a class annotated with @Module.

Is there are reason you can't just do this install this in the SingletonComponent directly:

Module
@InstallIn(SingletonComponent::class)
object DIModule {

    @DemoMode
    @Provides
    fun provideDataRepositoryImplDemo(): DataRepository =
        DataRepositoryImplDemo()

    @Provides
    @ProductionMode
    fun provideDataRepositoryImpl(): DataRepository =
        DataRepositoryImpl()
}

That seems to be the core of the issue here. I'm guessing its because of the custom component / scope. In that case, I think you just need to use EntryPoints where you are actually injecting the repositories:

class Sample {
    private lateinit var demoRepository: DataRepository
    private lateinit var productionRepository: DataRepository

    fun inject(authUserComponent: AuthUserComponent) {
       val entryPoint = EntryPoints.get(authUserComponent, AuthUserDataEntryPoint:class.java)
       demoRepository = entryPoint.demoRepositoryImpl()
       productionRepository = entryPoint.productionRepositoryImpl()
    }

}

But I don't think you're going to get away with trying to hide the EntryPoints usage inside a module definition.