-
-
Notifications
You must be signed in to change notification settings - Fork 771
Koin + Ktor DI 3.2 Integration #2250
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
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" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
even 3.2.2
| ?: resolveFromScopeSource(scope,instanceContext) | ||
| ?: resolveFromScopeArchetype(scope,instanceContext) | ||
| ?: if (lookupParent) resolveFromParentScopes(scope,instanceContext) else null | ||
| ?: (if (lookupParent) resolveFromParentScopes(scope,instanceContext) else null) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ok
|
|
||
| override fun contains(key: DependencyKey): Boolean = | ||
| try { | ||
| resolve(key) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ok, interesting. Thanks
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.
bjhham
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
👍
| // 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.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
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.