Home > Net >  How do you inject a specific subclass based on the which class is instantiated with Hilt?
How do you inject a specific subclass based on the which class is instantiated with Hilt?

Time:05-31

I have these Repositories dependent on DataSources.

class LocationRepository: Repository<String>(LocationDataSource())
class ItemRepository: Repository<String>(ItemDataSource())

I would like to inject the Repository class with Hilt like this to prevent code duplication.

abstract class Repository<T> {

    @Inject lateinit var dataSource: DataSource<T>
    ...
}

I have tried this, but am not sure how to get Hilt to use the right ones.

@Qualifier
@Retention(AnnotationRetention.BINARY)
annotation class ItemDataSourceAnnotation

@Qualifier
@Retention(AnnotationRetention.BINARY)
annotation class LocationDataSourceAnnotation

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

    @ItemDataSourceAnnotation
    @Provides
    @Singleton
    fun provideItemDataSource(): DataSource{
        return ItemDataSource()
    }

    @LocationDataSourceAnnotation
    @Provides
    @Singleton
    fun provideLocationDataSource(): DataSource{
        return LocationDataSource()
    }
}
@Module
@InstallIn(SingletonComponent::class)
object RepositoryModule {

    @Provides
    @Singleton
    fun providesItemRepository(
        @ItemDataSourceAnnotation itemDataSource: ItemDataSource
    ): ItemRepository {
        return ItemRepository()
    }
    
    @Provides
    @Singleton
    fun providesLocationRepository(
        @LocationDataSourceAnnotation locationDataSource: LocationDataSource
    ): LocationRepository {
        return LocationRepository()
    }
    
}

CodePudding user response:

If what you want is to avoid having the data source field in each repository subclass, you could add a data source type parameter and val to Repository:

class Repository<ValueT, DataSourceT>(val dataSource: DataSourceT) {
  ...
}

class LocationRepository: Repository<Location, LocationDataSource> @Inject constructor(dataSource: LocationDataSource): super(dataSource) {
  ...
}

It's better to use constructor injection than field injection, and using constructor injection, you have to pass the constructor parameters through the subclasses -- you can't do it only in the base class.

  • Related