Reputation: 1387
After scouring the internet, there doesn't seem to be a similar issue and it is eating me. In the process of learning Dependency Injection using Dagger 2, I am trying to translate an example from Java to Kotlin. The project compiles fine in Java, but using Kotlin, Does not like the javax.inject.Provider class and fails to build.
What is missing? Is the use of the Provider class incorrect for Kotlin here?
Here is the error from the Gradle event log:
repositorytrends\custom_implementations\RepoTrendsAppComponent.java:8: error: java.util.Map<java.lang.Class<? extends android.app.Activity>,? extends javax.inject.Provider<dagger.android.AndroidInjector.Factory<? extends android.app.Activity>>> cannot be provided without an @Provides-annotated method.
Here is the offending file. The parameter (Map) for the internal constructor is the deciding factor in a successful build:
class ActivityInjector
@Inject internal constructor(private val activityInjectors: Map<Class<out Activity>, Provider<AndroidInjector.Factory<out Activity>>>){
private val cache = HashMap<String, AndroidInjector<out Activity>>()
internal fun inject(activity: Activity) {
if (activity !is RepoTrendActivity) {
throw IllegalArgumentException("Activity must extend BaseActivity")
}
val instanceId = activity.getInstanceID
if (cache.containsKey(instanceId)) {
(cache[instanceId] as AndroidInjector<Activity>).inject(activity)
return
}
val injectorFactory = activityInjectors[activity.javaClass]?.get() as AndroidInjector.Factory<Activity>
val injector = injectorFactory.create(activity)
cache.put(instanceId, injector)
injector.inject(activity)
}
internal fun clear(activity: Activity) {
if (activity !is RepoTrendActivity) {
throw IllegalArgumentException("Activity must extend BaseActivity")
}
cache.remove(activity.getInstanceID)
}
companion object {
internal operator fun get(context: Context): ActivityInjector{
return (context.applicationContext as RepoTrendsApp).activityInjector
}
}
}
Here are the rest of the classes that are related to the Gradle build error log:
@Singleton
@Component(modules = arrayOf(
RepoTrendsAppModule::class
))
interface RepoTrendsAppComponent {
fun inject(repoTrendsApp: RepoTrendsApp)
}
Custom Application file:
class RepoTrendsApp: Application(){
@Inject lateinit var activityInjector: ActivityInjector
}
Build.gradle for good measure:
apply plugin: 'com.android.application'
apply plugin: 'kotlin-android'
apply plugin: 'kotlin-android-extensions'
apply plugin: 'kotlin-kapt'
android {
compileSdkVersion 26
defaultConfig {
applicationId 'com.inviscidlabs.repositorytrends'
minSdkVersion 21
targetSdkVersion 26
versionCode 1
versionName "1.0"
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
productFlavors {
}
kapt {
generateStubs = true
}
}
dependencies {
implementation"org.jetbrains.kotlin:kotlin-stdlib-jre7:$kotlin_version"
implementation "com.android.support:appcompat-v7:$supportLibraryVersion"
implementation "com.android.support:design:$supportLibraryVersion"
implementation "com.google.dagger:dagger:$daggerVersion"
implementation "com.google.dagger:dagger-android-support:$daggerVersion"
kapt "com.google.dagger:dagger-android-processor:$daggerVersion"
kapt "com.google.dagger:dagger-compiler:$daggerVersion"
implementation "com.squareup.retrofit2:retrofit:$retrofitVersion"
implementation "com.squareup.retrofit2:converter-moshi:$retrofitVersion"
implementation "com.squareup.moshi:moshi:$moshiVersion"
kapt "com.ryanharter.auto.value:auto-value-moshi:$autoValueMoshiVersion"
compileOnly "com.ryanharter.auto.value:auto-value-moshi-annotations:$autoValueMoshiVersion"
compileOnly "com.google.auto.value:auto-value:$autoValueVersion"
annotationProcessor "com.google.auto.value:auto-value:$autoValueVersion"
implementation "io.reactivex.rxjava2:rxjava:$rxJavaVersion"
implementation "io.reactivex.rxjava2:rxandroid:$rxAndroidVersion"
implementation "com.jakewharton.rxrelay2:rxrelay:$rxRelayVersion"
//Drop in replacement for Fragments
implementation "com.bluelinelabs:conductor:$conductorVersion"
testImplementation 'junit:junit:4.12'
androidTestImplementation 'com.android.support.test:runner:1.0.1'
androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.1'
implementation "org.jetbrains.kotlin:kotlin-stdlib-jre7:$kotlin_version"
implementation "org.jetbrains.kotlin:kotlin-stdlib-jre7:$kotlin_version"
implementation "org.jetbrains.kotlin:kotlin-reflect:$kotlin_version"
}
As requested, RepoTrendsAppModule:
import android.app.Application
import android.content.Context
import dagger.Module
import dagger.Provides
@Module
class RepoTrendsAppModule(val application: Application){
@Provides
fun provideApplicationContext(): Context = application
}
Upvotes: 0
Views: 2543
Reputation: 7368
You don't need your ActivityInjector
class. Modify your application class as follow:
class RepoTrendsApp: Application(), HasActivityInjector {
@Inject
internal lateinit var dispatchingActivityInjector: DispatchingAndroidInjector<Activity>
override fun onCreate() {
super.onCreate()
DaggerRepoTrendsAppComponent.builder()
.repoTrendsAppModule(RepoTrendsAppModule(this))
.build()
.inject(this)
}
override fun activityInjector(): AndroidInjector<Activity>? {
return dispatchingActivityInjector
}
}
and your component to:
@Singleton
@Component(modules = arrayOf(
AndroidSupportInjectionModule::class,
RepoTrendsAppModule::class
))
interface RepoTrendsAppComponent : AndroidInjector<RepoTrendsApp>
Upvotes: 1
Reputation: 307
Sounds like some the @Provides
annotation is missing on your module. Here's an example Kotlin/Android/Dagger 2 module definition:
@Module
class MyAndroidModule(private val application: Application) {
@Provides
@Singleton
@CustomInjectionAnnotation
fun provideApplicationContext(): Context = application
@Provides
@Singleton
fun provideLocationManager(): LocationManager =
application.getSystemService(Context.LOCATION_SERVICE) as LocationManager
@Provides
@Singleton
@Named("version")
fun provideVersionString(): String = "beta"
}
Upvotes: 0