I'm new to Dagger and have the following setup:
// data models
open class BaseEntity (open val id: Long)
data class UserEntity (override val id: Long, val name: String) : BaseEntity(id)
data class FruitEntity (override val id: Long, val status: String) : BaseEntity(id)
// interface to spec common API response operations
interface Repo<T> {
fun getEntities(): List<T>
}
// entity specific implementation of the repo interface
class RepoImpl<T: BaseEntity> @Inject constructor(apiService: ApiService) : Repo<T> {
override fun getEntities(): List<T> {
val entities = apiService.getEntities(...)// get result from respective entity network service, e.g users, fruits etc
return entities
}
}
// DI: provide entity-specific implementations of the interface
@Singleton
@Provides
fun provideUserRepoImpl(userService: UserApiService): RepoImpl<BaseEntity> {
return RepoImpl(userService)
}
@Singleton
@Provides
fun provideFruitRepoImpl(fruitService: FruitApiService): RepoImpl<BaseEntity> {
return RepoImpl(fruitService)
}
When I build the project, this error comes up:
error: RepoImpl<com.example.data.model.BaseEntity> is bound multiple times
...
@org.jetbrains.annotations.NotNull @Provides @Singleton com.example.data.source.remote.RepoImpl<com.example.data.model.BaseEntity> com.example.app.di.AppModule.provideUserRepoImpl()
@org.jetbrains.annotations.NotNull @Provides @Singleton com.example.data.source.remote.RepoImpl<com.example.data.model.BaseEntity> com.example.app.di.AppModule.provideFruitRepoImpl()
And when I try to provide the entity-specific instances, like this:
@Singleton
@Provides
fun provideUserRepoImpl(userService: UserApiService): RepoImpl<UserEntity> {
return RepoImpl(userService)
}
@Singleton
@Provides
fun provideFruitRepoImpl(fruitService: FruitApiService): RepoImpl<FruitEntity> {
return RepoImpl(fruitService)
}
I get the following:
error: RepoImpl<com.example.data.model.BaseEntity> cannot be provided without an @Inject constructor or from an @Provides-annotated method
Also I have tried separating the provider methods of fruits & users into their respective modules but latter error also comes up, maybe I'm not hooking up the FruitModule, UserModule and AppModule correctly. I'm having similar problems providing implementations of interfaces.
What would be a correct approach here, or is it not at all possible to inject parametrized classes with Dagger?
UPDATE
I have managed to solve the dependency issue on RepoImpl by explicitly providing each object to be injected (the latter option where we provide RepoImpl<UserEntity>
and RepoImpl<FruitEntity>
). I think the @Inject annotation on the constructor was somehow not being registered,
so had to refresh the project.
However, I cannot figure out how to provide implementations (or sub-types) of parametrized interfaces just yet. Consider for example the ApiService parameter of RepoImpl defined as follows:
// base service for all types of items
interface ApiService<T: BaseAttributes> {
fun getEntities(): T
}
// service impl for fruits
class FruitService : ApiService<FruitAttributes> {
override fun getEntities(): FruitResponses {...}
}
// service impl for users
class UserService : ApiService<UserAttributes> {
override fun getEntities(): UserResponses {...}
}
// AppModule.kt:
@Singleton
@Provides
fun provideUserService() : ApiService<UserAttributes> {
return UserService()
}
@Singleton
@Provides
fun provideFruitService() : ApiService<FruitAttributes> {
return FruitService()
}
error: "... ApiService<BaseAttributes> cannot be provided without an @Provides-annotated method ..."
whereas
...
fun provideUserService() : ApiService<BaseAttributes> {
return UserService() as ApiService<BaseAttributes>
}
...
fun provideFruitService() : ApiService<FruitAttributes> {
return FruitService() as ApiService<BaseAttributes>
}
error: "... ApiService<BaseAttributes> is bound multiple times: ..."
How else can I inject these implementations of the interface?