Photo by Ricardo Cruz on Unsplash

Migrating Dagger from Java to Kotlin

Posted: 12 Jul 2017. Last modified on 04-Jun-22.

This article will take about 2 minutes to read.


Kotlin is a wonderful language that lets us increase the safety of existing Java codebases. You may find yourself in a situation where you want to try it out, but are worried about the compatibility of frameworks you use. If you use Dagger2 for dependency injection, good news: Dagger in kotlin is mostly the same!

Injection

Injection works as normal, and is done via either a lateinit var or a val

@Singleton
class NewsManager @Inject constructor(private val api: NewsApi) {}

// OR

@Inject lateinit var newsManager: NewsManager

this ensures that the variable cannot be changed later, but we have to ensure that we do not use it before it is initialized (kotlin does not have default values for uninitialized fields, so null checks won’t save you.)

We would inject this like normal in a startup method of an Activity or Fragment.

Providers

When defining a provider, don’t infer type, make it explicit instead, as inferring leads to subtle bugs. Dagger will not be able to infer which type should be injected!

/*✅*/ @Provides fun provideDiskCache(): DiskCache { return DiskCache() }
/*✅*/ @Provides fun provideDiskCache(): DiskCache = DiskCache()
/*✅*/ @Provides fun provideDiskCache(): Cache { return DiskCache() }
/*✅*/ @Provides fun provideDiskCache(): Cache = DiskCache()

/*❌*/ @Provides fun provideDiskCache() = DiskCache() // we may be expecting type Cache instead  ¯\_(ツ)_/¯

Static providers

Static providers must be moved into the companion object. Notice that the @Module annotation has to be duplicated onto the companion object, so it will apply.

@Module
abstract class DataModule {
  @Binds abstract fun provideCache(diskCache: DiskCache): Cache

  @Module
  companion object {
    @JvmStatic
    @Provides
    fun provideDiskCache(): DiskCache = DiskCache()
  }
}

JvmField

@Named annotations will have to be prefixed with field

@Inject @field:Named("ioExecutor") lateinit var ioExecutor: Executor

The same goes for all injected properties

@Inject @field:ForApi lateinit var gson: Gson

For more information, see these articles