TL;DR

Inject is a new Kotlin multi-platform library that is a wrapper around the javax.inject annotations so that they can be used in Kotlin common code.

I recently created a new Kotlin Multi-platform library called inject which is a simple wrapper around the javax.inject annotations. The reason for creating this library was to allow Kotlin common code to be dependency injected using dagger on the JVM.

Dagger is a popular dependency injection library, used on Android and the JVM, which processes the javax.inject annotations to create a dependency graph during compile time. Though the library is often criticised for it's complexity and verbosity, it is one of the most performant solutions. And for this reason, is the most popular, especially on mobile environments. However, the downside is that this library is not available for Kotlin multi-platform code.

There are other Kotlin dependency injection and service locator libraries, such as, Koin, locator (which I created), and Kodein. The latter of which is a Kotlin multi-platform solution. Though I like the syntax of those libraries, I still tend to favor dagger because of it's performance and my familiarity with it.

Also, after pondering about it for awhile, I've come to the conclusion that dependency injection should be a platform specific concept. Each platform would be responsible for it's own dependency injection even when sharing common code.

For instance, there may be an interface in the common code with a corresponding implementation in each of the platform modules. Therefore the dependency creation couldn't occur in the common module due to it not knowing about each of the platform's implementations. This could possibly be solved using Kotlin's expect and actual keywords, but there's only so far an abstraction can be made as each implementation may require different platform specific code. For example, Android relies heavily on the Context framework class. This class is used for everything from retrieving resources to switching screens. This class is needed for many different reasons on Android but doesn't have a direct counterpart on iOS.

So, to avoid polluting the shared business logic in the common module with framework specific code, each platform module will handle their own dependency injection.

Then why this library?

Dependency injection using the dagger library requires constructors to be annotated with the javax.inject.Inject annotation. Though this is framework or platform specific code, the library needs annotations on the components it will inject so that the annotation processor can register the components and create the dependency graph (the Provides annotation could also be used but Inject is the more elegant and recommended approach). And since these annotations don't actually perform the dependency injection and just are metadata, I think it's fine to have them on Kotlin common code.

Using the library

The library is provided through Github Packages. Provide the repository in your build.gradle file:

repositories {
    maven {
        url = uri("https://maven.pkg.github.com/chrynan/inject")
    }
}

Then provide the dependencies in your build.gradle file:

dependencies {
    implementation("com.chrynan.inject:inject:VERSION")
}

Refer to the releases page for the most recent version.

Then you can use any of the available annotations. For example:

class MyPresenter @Inject constructor() : Presenter { ... }

The available annotations and interfaces are:

  • Inject
  • Named
  • Qualifier
  • Scope
  • Singleton
  • Provider

Conclusion

The new library I created, inject, allows you to annotate your Kotlin multi-platform common code with javax.inject annotations so that they can be processed in JVM platform modules to create a dependency graph.