Koin + Ktor DI 3.2 Integration#2250
Conversation
Ktor DI Bridge Implementation - Added KoinDependencyMapExtension implementing Ktor 3.2's DependencyMapExtension interface - Registered via SPI in META-INF/services/io.ktor.server.plugins.di.DependencyMapExtension Koin can resolve Ktor DI dependencies via KtorDIExtension resolution extension. - There is a potential problem with runBlocking usage When dependency is not found, each library is delegating to the other in an infinite loop Fixed a problem in CoreResolver that was not resolving extensions Created a sample application to show usage.
examples/gradle/versions.gradle
Outdated
|
|
||
| coroutines_version = "1.9.0" | ||
| ktor_version = "3.1.3"//"3.2.0-eap-1310" | ||
| ktor_version = "3.2.1" |
| ?: resolveFromScopeSource(scope,instanceContext) | ||
| ?: resolveFromScopeArchetype(scope,instanceContext) | ||
| ?: if (lookupParent) resolveFromParentScopes(scope,instanceContext) else null | ||
| ?: (if (lookupParent) resolveFromParentScopes(scope,instanceContext) else null) |
|
|
||
| override fun contains(key: DependencyKey): Boolean = | ||
| try { | ||
| resolve(key) |
There was a problem hiding this comment.
Let me check if we have a lookup check here, else we are directly resolving the key
| // The blocking call is generally safe as dependency resolution is typically fast and non-blocking | ||
| // WARNING: This may cause problems for users as it can impact performance | ||
| return runBlocking { | ||
| application.dependencies.get(key) |
There was a problem hiding this comment.
@osipxd we can't use getDeferred here, as we don't have reified type info from this point. we only have KClass.
Not sure runBlocking is the good way. Else we can go with typeOf() or something ?
There was a problem hiding this comment.
The key construction using the class reference looks right since the reified type's not available.
You can use application.dependencies.getBlocking(key) here to let Ktor handle the blocking part.
In the case of property delegates, we also have a step to indicate that the key should be checked during startup validation, which might be applicable elsewhere:
public inline operator fun <reified T> provideDelegate(
thisRef: Any?,
prop: KProperty<*>
): ReadOnlyProperty<Any?, T> {
val key = DependencyKey<T>()
.also(::require)
return ReadOnlyProperty { _, _ ->
getBlocking(key)
}
}There was a problem hiding this comment.
@bjhham one question: if Ktor DI is falling back on Koin and Koin falling back on Ktor DI, we might go with looping when none of the DIs have a given definition
There was a problem hiding this comment.
Will need to either reference the unextended counterparts as the fallbacks, or introduce a flag in the qualifier to break the loop, or just allow the bridge to call in one direction.
| // The blocking call is generally safe as dependency resolution is typically fast and non-blocking | ||
| // WARNING: This may cause problems for users as it can impact performance | ||
| return runBlocking { | ||
| application.dependencies.get(key) |
There was a problem hiding this comment.
The key construction using the class reference looks right since the reified type's not available.
You can use application.dependencies.getBlocking(key) here to let Ktor handle the blocking part.
In the case of property delegates, we also have a step to indicate that the key should be checked during startup validation, which might be applicable elsewhere:
public inline operator fun <reified T> provideDelegate(
thisRef: Any?,
prop: KProperty<*>
): ReadOnlyProperty<Any?, T> {
val key = DependencyKey<T>()
.also(::require)
return ReadOnlyProperty { _, _ ->
getBlocking(key)
}
}|
Thanks @bjhham for the Since we need this to work across all Kotlin targets, we might need to stick with the current approach or implement a platform-specific solution: expect fun <T> getDependencyBlocking(dependencies: DependencyMap, key: DependencyKey<T>): T
// JVM/Native implementation
actual fun <T> getDependencyBlocking(dependencies: DependencyMap, key: DependencyKey<T>): T =
dependencies.getBlocking(key)
// JS/WASM implementation
actual fun <T> getDependencyBlocking(dependencies: DependencyMap, key: DependencyKey<T>): T =
runBlocking { dependencies.get(key) }This way we get the benefits of Thoughts on this approach? |
|
Hey @lidonis you can use |
|
@bjhham the dependency key is forged with targeted class: Trying to ask Ktor DI for a given class, already declared in dependencies section: |
|
I follow it in #2294 |



Ktor DI Bridge Implementation
Koin can resolve Ktor DI dependencies via KtorDIExtension resolution extension.
When dependency is not found, each library is delegating to the other in an infinite loop
Fixed a problem in CoreResolver that was not resolving extensions
Created a sample application to show usage.