Skip to content

Basic resolver of dependencies for constructor-based dependency injection of Kotlin classes.

License

Notifications You must be signed in to change notification settings

evestera/kotlin-dependency-injection

Folders and files

NameName
Last commit message
Last commit date

Latest commit

4b506b9 · Oct 27, 2022

History

5 Commits
Oct 27, 2022
Oct 27, 2022
Oct 27, 2022
Oct 27, 2022
Oct 27, 2022
Oct 27, 2022
Oct 27, 2022
Oct 27, 2022
Oct 27, 2022
Oct 27, 2022
Oct 27, 2022
Oct 27, 2022
Oct 27, 2022
Oct 27, 2022
Oct 27, 2022

Repository files navigation

kotlin-dependency-injection

Basic resolver of dependencies for constructor-based dependency injection of Kotlin classes.

  • Self-contained. Classes being constructed do not need to know about this library.
  • Low maintenance. Adding or removing pre-existing classes as dependencies requires no changes to DI setup code.
  • Intentionally quite restricted to promote predictability and ease of understanding:
    • Only Kotlin classes with a primary constructor can be automatically constructed from a class reference. Other types are added as values or unambiguous function references (e.g. to a constructor or factory function).
    • No optional parameters allowed (though they can be ignored with @DoNotResolve).
    • Dependencies are resolvable either by type or by name, not both.
    • No ambiguous resolution. If two values are valid an exception is thrown instead.

Using

In build.gradle.kts:

dependencies {
    implementation("dev.vstrs:kotlin-dependency-injection:0.1.0")
}

Basic usage

// Given a set of classes depending on each other...
class CheeseRepository
class CheeseService(private val cheeseRepository: CheeseRepository)
class App(private val cheeseService: CheeseService)

// ...you can construct a context...
val context = DependencyResolutionContext.Builder().add(
    CheeseRepository::class,
    CheeseService::class,
    App::class
).build()

// ...and get the instances you need (probably the constructed app).
// You can throw away the context afterwards if you don't need it.
val app = context.get<App>()

In very simple cases like the above you can also just do

val app = resolveDependenciesAndGet<App>(
    CheeseRepository::class,
    CheeseService::class,
    App::class
)

Injecting by name

See @ResolveByName

Injecting all implementations of an interface

See @ResolveAll

Function references and values

You can use other things than just classes for dependency resolution. Direct values from calls like Clock.systemUTC() and function references like ::someFunction can be used.

The function references have to be unambiguous references to public functions. It is not currently possible to use inline lambdas as factory functions.

Example:

fun dbConfig(appConfig: AppConfig) = appConfig.db

fun createDbClient(dbConfig: DbConfig): DbClient {
    // do something with dbConfig
}

val app = resolveDependenciesAndGet<App>(
    Clock.systemUTC(),
    AppConfig::class,
    ::dbConfig,
    ::connectionPool,
    // ... more stuff using Clock and DbClient ...
    App::class
)

About

Basic resolver of dependencies for constructor-based dependency injection of Kotlin classes.

Topics

Resources

License

Stars

Watchers

Forks

Languages