diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 0be60719d..e84dc3ca8 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -1,6 +1,6 @@ name: Build & Test -on: pull_request: +on: pull_request concurrency: group: build-${{ github.ref }} diff --git a/CONTRIBUTING.adoc b/CONTRIBUTING.adoc index 413464c53..ab2bfe2d6 100644 --- a/CONTRIBUTING.adoc +++ b/CONTRIBUTING.adoc @@ -48,7 +48,7 @@ https://developer.android.com/studio/[AndroidStudio] === Building from source To build the source you will need to install -https://gradle.org/[Gradle] v4.7 or more. +https://gradle.org/[Gradle] v7.4.2 or more. We use Gradlew in the build scripts diff --git a/android/build.gradle b/android/build.gradle index 47cb866d0..c0da19f12 100644 --- a/android/build.gradle +++ b/android/build.gradle @@ -6,7 +6,6 @@ buildscript { mavenLocal() mavenCentral() google() - jcenter() //TODO replace io.mockk } dependencies { @@ -32,7 +31,6 @@ allprojects { mavenLocal() mavenCentral() google() - jcenter() } group = 'io.insert-koin' @@ -53,8 +51,6 @@ allprojects { kotlinOptions { jvmTarget = '1.8' - apiVersion = '1.5' - languageVersion = '1.5' } } -} \ No newline at end of file +} diff --git a/android/gradle/versions.gradle b/android/gradle/versions.gradle index 050652523..a3470f20f 100644 --- a/android/gradle/versions.gradle +++ b/android/gradle/versions.gradle @@ -1,6 +1,6 @@ ext { // Koin Versions - koin_android_version = '3.5.0' + koin_android_version = '3.5.3' // build Tools android_min_version = 14 diff --git a/android/koin-android/build.gradle b/android/koin-android/build.gradle index afc2c4647..1d8debf08 100644 --- a/android/koin-android/build.gradle +++ b/android/koin-android/build.gradle @@ -29,9 +29,9 @@ dependencies { api "androidx.appcompat:appcompat:1.6.1" api "androidx.activity:activity-ktx:1.7.2" - api "androidx.fragment:fragment-ktx:1.6.1" - api "androidx.lifecycle:lifecycle-viewmodel-ktx:2.6.1" - api("androidx.lifecycle:lifecycle-common-java8:2.6.1") + api "androidx.fragment:fragment-ktx:1.6.2" + api "androidx.lifecycle:lifecycle-viewmodel-ktx:2.6.2" + api("androidx.lifecycle:lifecycle-common-java8:2.6.2") // tests testImplementation "io.insert-koin:koin-test:$koin_version" diff --git a/android/koin-android/src/main/java/org/koin/androidx/viewmodel/GetViewModel.kt b/android/koin-android/src/main/java/org/koin/androidx/viewmodel/GetViewModel.kt index 9b8971f27..1e8a9ac1c 100644 --- a/android/koin-android/src/main/java/org/koin/androidx/viewmodel/GetViewModel.kt +++ b/android/koin-android/src/main/java/org/koin/androidx/viewmodel/GetViewModel.kt @@ -1,7 +1,6 @@ package org.koin.androidx.viewmodel import androidx.annotation.MainThread -import androidx.lifecycle.SavedStateHandle import androidx.lifecycle.ViewModel import androidx.lifecycle.ViewModelProvider import androidx.lifecycle.ViewModelStore @@ -38,13 +37,25 @@ fun resolveViewModel( val modelClass: Class = vmClass.java val factory = KoinViewModelFactory(vmClass, scope, qualifier, parameters) val provider = ViewModelProvider(viewModelStore, factory, extras) + val vmKey = getViewModelKey(qualifier, scope, key) return when { - qualifier != null -> provider[qualifier.value + (key?.let { "_$it" } ?: ""), modelClass] - key != null -> provider[key, modelClass] + vmKey != null -> provider[vmKey, modelClass] else -> provider[modelClass] } } +@KoinInternalApi +internal fun getViewModelKey(qualifier: Qualifier?, scope: Scope, key: String?): String? { + return if (qualifier == null && key == null && scope.isRoot) { + null + } else { + val q = qualifier?.value ?: "" + val k = key ?: "" + val s = if (!scope.isRoot) scope.id else "" + "$q$k$s" + } +} + /** * Resolve a Lazy ViewModel instance * used in Main Thread @@ -68,5 +79,15 @@ fun lazyResolveViewModel( scope: Scope, parameters: (() -> ParametersHolder)? = null, ): Lazy { - return lazy(LazyThreadSafetyMode.NONE) { resolveViewModel(vmClass, viewModelStore(), key, extras(), qualifier, scope, parameters) } + return lazy(LazyThreadSafetyMode.NONE) { + resolveViewModel( + vmClass, + viewModelStore(), + key, + extras(), + qualifier, + scope, + parameters + ) + } } \ No newline at end of file diff --git a/android/koin-android/src/main/java/org/koin/androidx/viewmodel/ext/android/FragmentActivityVM.kt b/android/koin-android/src/main/java/org/koin/androidx/viewmodel/ext/android/FragmentActivityVM.kt index 5a66655cf..fbe39f5e5 100644 --- a/android/koin-android/src/main/java/org/koin/androidx/viewmodel/ext/android/FragmentActivityVM.kt +++ b/android/koin-android/src/main/java/org/koin/androidx/viewmodel/ext/android/FragmentActivityVM.kt @@ -15,6 +15,8 @@ */ package org.koin.androidx.viewmodel.ext.android +import android.app.Activity +import androidx.activity.ComponentActivity import androidx.annotation.MainThread import androidx.fragment.app.Fragment import androidx.lifecycle.ViewModel @@ -66,10 +68,11 @@ inline fun Fragment.getActivityViewModel( noinline extrasProducer: (() -> CreationExtras)? = null, noinline parameters: (() -> ParametersHolder)? = null, ): T { + val op = ownerProducer() return resolveViewModel( T::class, - ownerProducer().viewModelStore, - extras = extrasProducer?.invoke() ?: this.defaultViewModelCreationExtras, + op.viewModelStore, + extras = extrasProducer?.invoke() ?: (op as? ComponentActivity)?.defaultViewModelCreationExtras ?: this.defaultViewModelCreationExtras, qualifier = qualifier, parameters = parameters, scope = getKoinScope() diff --git a/android/koin-android/src/test/java/org/koin/test/android/viewmodel/ViewModelKeyTest.kt b/android/koin-android/src/test/java/org/koin/test/android/viewmodel/ViewModelKeyTest.kt new file mode 100644 index 000000000..7882d5b87 --- /dev/null +++ b/android/koin-android/src/test/java/org/koin/test/android/viewmodel/ViewModelKeyTest.kt @@ -0,0 +1,44 @@ +package org.koin.test.android.viewmodel + +import org.junit.Test +import org.koin.androidx.viewmodel.getViewModelKey +import org.koin.core.annotation.KoinInternalApi +import org.koin.core.qualifier.StringQualifier +import org.koin.core.scope.Scope +import org.koin.dsl.koinApplication +import kotlin.test.assertEquals + +class ViewModelKeyTest { + + @OptIn(KoinInternalApi::class) + @Test + fun generate_right_key() { + val koin = koinApplication().koin + val root = koin.scopeRegistry.rootScope + + val q = StringQualifier("_qualifier_") + val scope = Scope(StringQualifier("_q_"), id = "_id_", _koin = koin, isRoot = false) + val key = "_KEY_" + + assertEquals( + null, getViewModelKey(qualifier = null, scope = root, key = null) + ) + assertEquals( + q.value, getViewModelKey(qualifier = q, scope = root, key = null) + ) + assertEquals( + key, getViewModelKey(qualifier = null, scope = root, key = key) + ) + assertEquals( + scope.id, getViewModelKey(qualifier = null, scope = scope, key = null) + ) + + assertEquals( + key + scope.id, getViewModelKey(qualifier = null, scope = scope, key = key) + ) + + assertEquals( + q.value + key + scope.id, getViewModelKey(qualifier = q, scope = scope, key = key) + ) + } +} \ No newline at end of file diff --git a/android/koin-androidx-navigation/build.gradle b/android/koin-androidx-navigation/build.gradle index 95f13cc6f..55a405827 100644 --- a/android/koin-androidx-navigation/build.gradle +++ b/android/koin-androidx-navigation/build.gradle @@ -35,7 +35,7 @@ dependencies { api project(":koin-android") // Android - api "androidx.navigation:navigation-fragment-ktx:2.7.1" + api "androidx.navigation:navigation-fragment-ktx:2.7.5" } apply from: '../../gradle/publish-to-central.gradle' diff --git a/bom/gradle/versions.gradle b/bom/gradle/versions.gradle index 8418bf6e1..e3a98225e 100644 --- a/bom/gradle/versions.gradle +++ b/bom/gradle/versions.gradle @@ -1,3 +1,3 @@ ext { - koin_bom_version = '3.5.1' + koin_bom_version = '3.5.3' } \ No newline at end of file diff --git a/compose/build.gradle b/compose/build.gradle index 69e8046f9..c0e7e34ef 100644 --- a/compose/build.gradle +++ b/compose/build.gradle @@ -8,6 +8,7 @@ buildscript { mavenCentral() mavenLocal() maven { url "https://maven.pkg.jetbrains.space/public/p/kotlinx-html/maven" } + maven { url 'https://androidx.dev/storage/compose-compiler/repository/' } } dependencies { // Kotlin @@ -35,6 +36,7 @@ allprojects { mavenCentral() mavenLocal() maven { url "https://maven.pkg.jetbrains.space/public/p/kotlinx-html/maven" } + maven { url 'https://androidx.dev/storage/compose-compiler/repository/' } } group = 'io.insert-koin' diff --git a/compose/gradle/versions.gradle b/compose/gradle/versions.gradle index 450d077f2..68e7749e2 100644 --- a/compose/gradle/versions.gradle +++ b/compose/gradle/versions.gradle @@ -1,17 +1,17 @@ ext { // Koin Versions - koin_androidx_compose_version = '3.5.0' - koin_compose_version = "1.1.0" + koin_androidx_compose_version = '3.5.3' + koin_compose_version = "1.1.2" // Compose - compose_compiler = "1.5.0" + compose_compiler = "1.5.6" // JB Compose - jb_compose_version = "1.5.0" + jb_compose_version = "1.5.11" // Forced Version to keep compat - kotlin_version = '1.9.0' - koin_version = '3.5.0' - koin_android_version = '3.5.0' +// kotlin_version = '1.9.20' +// koin_version = '3.5.2-RC2' +// koin_android_version = '3.5.2-RC2' } \ No newline at end of file diff --git a/compose/koin-androidx-compose-navigation/build.gradle b/compose/koin-androidx-compose-navigation/build.gradle index 8f9a6f268..c42124a70 100644 --- a/compose/koin-androidx-compose-navigation/build.gradle +++ b/compose/koin-androidx-compose-navigation/build.gradle @@ -40,7 +40,7 @@ dependencies { // Koin api project(":koin-androidx-compose") // Navigation - api "androidx.navigation:navigation-compose:2.7.1" + api "androidx.navigation:navigation-compose:2.7.5" } apply from: '../../gradle/publish-to-central.gradle' diff --git a/compose/koin-androidx-compose-navigation/src/main/java/org/koin/androidx/compose/navigation/NavViewModel.kt b/compose/koin-androidx-compose-navigation/src/main/java/org/koin/androidx/compose/navigation/NavViewModel.kt index 413c5493f..36f4606c4 100644 --- a/compose/koin-androidx-compose-navigation/src/main/java/org/koin/androidx/compose/navigation/NavViewModel.kt +++ b/compose/koin-androidx-compose-navigation/src/main/java/org/koin/androidx/compose/navigation/NavViewModel.kt @@ -23,7 +23,7 @@ import androidx.lifecycle.viewmodel.CreationExtras import androidx.lifecycle.viewmodel.compose.LocalViewModelStoreOwner import org.koin.androidx.viewmodel.resolveViewModel import org.koin.compose.LocalKoinScope -import org.koin.compose.getKoinScope +import org.koin.compose.currentKoinScope import org.koin.core.annotation.KoinInternalApi import org.koin.core.parameter.ParametersDefinition import org.koin.core.qualifier.Qualifier @@ -46,7 +46,7 @@ inline fun koinNavViewModel( }, key: String? = null, extras: CreationExtras = defaultNavExtras(viewModelStoreOwner), - scope: Scope = getKoinScope(), + scope: Scope = currentKoinScope(), noinline parameters: ParametersDefinition? = null, ): T { return resolveViewModel( diff --git a/compose/koin-androidx-compose/build.gradle b/compose/koin-androidx-compose/build.gradle index 0b464d0a5..d1e673ea4 100644 --- a/compose/koin-androidx-compose/build.gradle +++ b/compose/koin-androidx-compose/build.gradle @@ -44,8 +44,8 @@ dependencies { api "io.insert-koin:koin-android:$koin_android_version" api project(":koin-compose") // Compose - api "androidx.compose.runtime:runtime:1.5.0" - api "androidx.lifecycle:lifecycle-viewmodel-compose:2.6.1" + api "androidx.compose.runtime:runtime:1.5.4" + api "androidx.lifecycle:lifecycle-viewmodel-compose:2.6.2" } apply from: '../../gradle/publish-to-central.gradle' diff --git a/compose/koin-androidx-compose/src/main/java/org/koin/androidx/compose/GetExt.kt b/compose/koin-androidx-compose/src/main/java/org/koin/androidx/compose/GetExt.kt index 58fe73ec0..7279ae836 100644 --- a/compose/koin-androidx-compose/src/main/java/org/koin/androidx/compose/GetExt.kt +++ b/compose/koin-androidx-compose/src/main/java/org/koin/androidx/compose/GetExt.kt @@ -17,7 +17,8 @@ package org.koin.androidx.compose import androidx.compose.runtime.Composable import androidx.compose.runtime.remember -import org.koin.compose.getKoinScope +import org.koin.compose.currentKoinScope +import org.koin.compose.rememberCurrentKoinScope import org.koin.core.Koin import org.koin.core.annotation.KoinInternalApi import org.koin.core.context.GlobalContext @@ -40,7 +41,7 @@ import org.koin.core.scope.Scope @Deprecated("use koinInject() instead") inline fun get( qualifier: Qualifier? = null, - scope: Scope = getKoinScope(), + scope: Scope = currentKoinScope(), noinline parameters: ParametersDefinition? = null, ): T = remember(qualifier, parameters, scope) { scope.get(qualifier, parameters) diff --git a/compose/koin-androidx-compose/src/main/java/org/koin/androidx/compose/ViewModel.kt b/compose/koin-androidx-compose/src/main/java/org/koin/androidx/compose/ViewModel.kt index 0dd577720..efa0466e3 100644 --- a/compose/koin-androidx-compose/src/main/java/org/koin/androidx/compose/ViewModel.kt +++ b/compose/koin-androidx-compose/src/main/java/org/koin/androidx/compose/ViewModel.kt @@ -23,7 +23,8 @@ import androidx.lifecycle.viewmodel.CreationExtras import androidx.lifecycle.viewmodel.compose.LocalViewModelStoreOwner import org.koin.androidx.viewmodel.resolveViewModel import org.koin.compose.LocalKoinScope -import org.koin.compose.getKoinScope +import org.koin.compose.currentKoinScope +import org.koin.compose.rememberCurrentKoinScope import org.koin.core.annotation.KoinInternalApi import org.koin.core.parameter.ParametersDefinition import org.koin.core.qualifier.Qualifier @@ -39,6 +40,7 @@ import org.koin.core.scope.Scope */ @Composable +@Deprecated("use koinViewModel() instead", replaceWith = ReplaceWith("koinViewModel")) inline fun getViewModel( qualifier: Qualifier? = null, viewModelStoreOwner: ViewModelStoreOwner = checkNotNull(LocalViewModelStoreOwner.current) { @@ -46,7 +48,7 @@ inline fun getViewModel( }, key: String? = null, extras: CreationExtras = defaultExtras(viewModelStoreOwner), - scope: Scope = getKoinScope(), + scope: Scope = rememberCurrentKoinScope(), noinline parameters: ParametersDefinition? = null, ): T { return koinViewModel(qualifier, viewModelStoreOwner, key, extras, scope, parameters) @@ -61,7 +63,7 @@ inline fun koinViewModel( }, key: String? = null, extras: CreationExtras = defaultExtras(viewModelStoreOwner), - scope: Scope = getKoinScope(), + scope: Scope = currentKoinScope(), noinline parameters: ParametersDefinition? = null, ): T { return resolveViewModel( diff --git a/compose/koin-androidx-compose/src/main/java/org/koin/androidx/compose/scope/KoinAndroidScope.kt b/compose/koin-androidx-compose/src/main/java/org/koin/androidx/compose/scope/KoinAndroidScope.kt index b044ff82b..acfb56e6d 100644 --- a/compose/koin-androidx-compose/src/main/java/org/koin/androidx/compose/scope/KoinAndroidScope.kt +++ b/compose/koin-androidx-compose/src/main/java/org/koin/androidx/compose/scope/KoinAndroidScope.kt @@ -20,7 +20,6 @@ import androidx.compose.runtime.CompositionLocalProvider import androidx.compose.ui.platform.LocalContext import org.koin.android.scope.AndroidScopeComponent import org.koin.compose.LocalKoinScope -import org.koin.compose.getKoinScope @Composable diff --git a/compose/koin-compose/src/commonMain/kotlin/org/koin/compose/Inject.kt b/compose/koin-compose/src/commonMain/kotlin/org/koin/compose/Inject.kt index 698baa57d..a8a731a0b 100644 --- a/compose/koin-compose/src/commonMain/kotlin/org/koin/compose/Inject.kt +++ b/compose/koin-compose/src/commonMain/kotlin/org/koin/compose/Inject.kt @@ -34,9 +34,14 @@ import org.koin.core.scope.Scope @Composable inline fun koinInject( qualifier: Qualifier? = null, - scope: Scope = getKoinScope(), + scope: Scope = currentKoinScope(), noinline parameters: ParametersDefinition? = null, -): T = rememberKoinInject(qualifier, scope, parameters) +): T { + val st = parameters?.let { rememberStableParametersDefinition(parameters) } + return remember(qualifier, scope) { + scope.get(qualifier, st?.parametersDefinition) + } +} /** * alias of koinInject() @@ -46,13 +51,14 @@ inline fun koinInject( * @author Arnaud Giuliani */ @Composable +@Deprecated("") inline fun rememberKoinInject( qualifier: Qualifier? = null, - scope: Scope = getKoinScope(), + scope: Scope = rememberCurrentKoinScope(), noinline parameters: ParametersDefinition? = null, ): T { - val st = rememberStableParametersDefinition(parameters) + val st = parameters?.let { rememberStableParametersDefinition(parameters) } return remember(qualifier, scope) { - scope.get(qualifier, st.parametersDefinition) + scope.get(qualifier, st?.parametersDefinition) } } diff --git a/compose/koin-compose/src/commonMain/kotlin/org/koin/compose/KoinApplication.kt b/compose/koin-compose/src/commonMain/kotlin/org/koin/compose/KoinApplication.kt index 880e51241..6f95a0f83 100644 --- a/compose/koin-compose/src/commonMain/kotlin/org/koin/compose/KoinApplication.kt +++ b/compose/koin-compose/src/commonMain/kotlin/org/koin/compose/KoinApplication.kt @@ -25,49 +25,44 @@ import androidx.compose.runtime.ProvidableCompositionLocal import androidx.compose.runtime.compositionLocalOf import androidx.compose.runtime.currentComposer import androidx.compose.runtime.remember -import org.koin.compose.error.UnknownKoinContext import org.koin.core.Koin import org.koin.core.KoinApplication import org.koin.core.annotation.KoinInternalApi -import org.koin.core.module.Module +import org.koin.core.context.startKoin +import org.koin.core.error.ApplicationAlreadyStartedException import org.koin.core.scope.Scope import org.koin.dsl.KoinAppDeclaration -import org.koin.dsl.koinApplication +import org.koin.mp.KoinPlatform import org.koin.mp.KoinPlatformTools /** * Current Koin Application context */ val LocalKoinApplication: ProvidableCompositionLocal = compositionLocalOf { - throw UnknownKoinContext() + getDefaultKoinContext().apply { + warnNoContext() + } } /** * Current Koin Scope */ val LocalKoinScope: ProvidableCompositionLocal = compositionLocalOf { - throw UnknownKoinContext() + getDefaultKoinContext().apply { + warnNoContext() + }.scopeRegistry.rootScope } -private fun getKoinContext() = KoinPlatformTools.defaultContext().get() +private fun getDefaultKoinContext() = KoinPlatformTools.defaultContext().get() /** * Retrieve the current Koin application from the composition. * * @author @author jjkester */ -@OptIn(InternalComposeApi::class) @Composable fun getKoin(): Koin = currentComposer.run { - remember { - try { - consume(LocalKoinApplication) - } catch (_: UnknownKoinContext) { - val ctx = getKoinContext() - warningNoContext(ctx) - ctx - } - } + return LocalKoinApplication.current } /** @@ -76,60 +71,54 @@ fun getKoin(): Koin = currentComposer.run { * @author @author jjkester * */ -@OptIn(InternalComposeApi::class) @Composable -fun getKoinScope(): Scope = currentComposer.run { - remember { - try { - consume(LocalKoinScope) - } catch (_: UnknownKoinContext) { - val ctx = getKoinContext() - warningNoContext(ctx) - getKoinContext().scopeRegistry.rootScope - } - } -} - -private fun warningNoContext(ctx: Koin) { - ctx.logger.error("[Warning] - No Compose Koin context setup, taking default. Use KoinContext(), KoinAndroidContext() or KoinApplication() function to setup or create Koin context and avoid such message.") +fun currentKoinScope(): Scope = currentComposer.run { + return LocalKoinScope.current } /** - * Start a new Koin Application in Compose context + * Retrieve the current Koin scope from the composition * - * @param application - Koin Application declaration lambda (like startKoin) - * @param content - following compose function + * @author @author jjkester * - * @author Arnaud Giuliani */ +@OptIn(InternalComposeApi::class) @Composable -fun KoinApplication( - application: KoinAppDeclaration, - content: @Composable () -> Unit -) { - val koinApplication = remember(application) { koinApplication(appDeclaration = application) } - CompositionLocalProvider( - LocalKoinApplication provides koinApplication.koin, - LocalKoinScope provides koinApplication.koin.scopeRegistry.rootScope - ) { - content() +fun rememberCurrentKoinScope(): Scope = currentComposer.run { + remember { + consume(LocalKoinScope) } } +@OptIn(KoinInternalApi::class) +private fun Koin.warnNoContext() { + logger.info("[Warning] - No Koin context defined in Compose, fallback to default Koin context.\nUse KoinContext(), KoinAndroidContext() or KoinApplication() to setup or create Koin context with Compose and avoid such message.") +} + /** - * Create a new Koin Application context for Compose + * Start a new Koin Application and associate it for Compose context + * if Koin's Default Context is already set, * - * @param moduleList - list of Modules to run within Koin Application + * @param application - Koin Application declaration lambda (like startKoin) * @param content - following compose function * + * @throws ApplicationAlreadyStartedException * @author Arnaud Giuliani */ @Composable +@Throws(ApplicationAlreadyStartedException::class) fun KoinApplication( - moduleList: () -> List, + application: KoinAppDeclaration, content: @Composable () -> Unit ) { - val koinApplication = remember(moduleList) { koinApplication { modules(moduleList()) } } + val koinApplication = remember(application) { + val alreadyExists = KoinPlatformTools.defaultContext().getOrNull() != null + if (alreadyExists) { + throw ApplicationAlreadyStartedException("Trying to run new Koin Application whereas Koin is already started. Use 'KoinContext()' instead of check for any 'startKoin' usage. ") + } else { + startKoin(application) + } + } CompositionLocalProvider( LocalKoinApplication provides koinApplication.koin, LocalKoinScope provides koinApplication.koin.scopeRegistry.rootScope @@ -139,7 +128,7 @@ fun KoinApplication( } /** - * Run and bind Compose with existing Koin context + * Use Compose with current existing Koin context, by default 'KoinPlatform.getKoin()' * * @see KoinPlatformTools.defaultContext() * @param content - following compose function @@ -148,7 +137,7 @@ fun KoinApplication( */ @Composable fun KoinContext( - context: Koin = KoinPlatformTools.defaultContext().get(), + context: Koin = KoinPlatform.getKoin(), content: @Composable () -> Unit ) { CompositionLocalProvider( diff --git a/compose/koin-compose/src/commonMain/kotlin/org/koin/compose/scope/KoinScope.kt b/compose/koin-compose/src/commonMain/kotlin/org/koin/compose/scope/KoinScope.kt index 157d2ba77..049754020 100644 --- a/compose/koin-compose/src/commonMain/kotlin/org/koin/compose/scope/KoinScope.kt +++ b/compose/koin-compose/src/commonMain/kotlin/org/koin/compose/scope/KoinScope.kt @@ -21,7 +21,6 @@ import org.koin.compose.LocalKoinScope import org.koin.compose.getKoin import org.koin.core.Koin import org.koin.core.annotation.KoinExperimentalAPI -import org.koin.core.component.getScopeId import org.koin.core.qualifier.Qualifier import org.koin.core.scope.Scope import org.koin.core.scope.ScopeID @@ -42,7 +41,7 @@ fun KoinScope( content: @Composable () -> Unit ) { val scope = scopeDefinition(getKoin()) - RememberScope(scope, content) + OnKoinScope(scope, content) } /** @@ -61,38 +60,7 @@ inline fun KoinScope( noinline content: @Composable () -> Unit ) { val scope = getKoin().getOrCreateScope(scopeID) - RememberScope(scope, content) -} - -@KoinExperimentalAPI -@Composable -@PublishedApi -internal fun RememberScope(scope: Scope, content: @Composable () -> Unit) { - rememberKoinScope(scope) - CompositionLocalProvider( - LocalKoinScope provides scope, - ) { - content() - } -} - -/** - * Create Koin Scope from context & close it when Composition is on onForgotten/onAbandoned - * - * @param context - * - * @see rememberKoinScope - * - * @author Arnaud Giuliani - */ -@KoinExperimentalAPI -@Composable -inline fun KoinScope( - context : Any, - noinline content: @Composable () -> Unit -) { - val scope = getKoin().getOrCreateScope(context.getScopeId()) - RememberScope(scope, content) + OnKoinScope(scope, content) } /** @@ -113,5 +81,17 @@ inline fun KoinScope( noinline content: @Composable () -> Unit ) { val scope = getKoin().getOrCreateScope(scopeID, scopeQualifier) - RememberScope(scope, content) + OnKoinScope(scope, content) +} + +@KoinExperimentalAPI +@Composable +@PublishedApi +internal fun OnKoinScope(scope: Scope, content: @Composable () -> Unit) { + rememberKoinScope(scope) + CompositionLocalProvider( + LocalKoinScope provides scope, + ) { + content() + } } \ No newline at end of file diff --git a/compose/koin-compose/src/commonMain/kotlin/org/koin/compose/scope/RememberScopes.kt b/compose/koin-compose/src/commonMain/kotlin/org/koin/compose/scope/RememberScopes.kt index f118d8625..6ceb09e0c 100644 --- a/compose/koin-compose/src/commonMain/kotlin/org/koin/compose/scope/RememberScopes.kt +++ b/compose/koin-compose/src/commonMain/kotlin/org/koin/compose/scope/RememberScopes.kt @@ -20,13 +20,18 @@ package org.koin.compose.scope import androidx.compose.runtime.Composable import androidx.compose.runtime.remember import org.koin.compose.getKoin +import org.koin.core.Koin import org.koin.core.annotation.KoinExperimentalAPI import org.koin.core.annotation.KoinInternalApi +import org.koin.core.qualifier.Qualifier +import org.koin.core.qualifier.StringQualifier import org.koin.core.scope.Scope +import org.koin.core.scope.ScopeID /** * Remember Koin Scope & run CompositionKoinScopeLoader to handle scope closure * + * @param scope - Koin scope * @author Arnaud Giuliani */ @KoinExperimentalAPI diff --git a/compose/sample-android-compose/src/main/java/org/koin/sample/androidx/compose/App.kt b/compose/sample-android-compose/src/main/java/org/koin/sample/androidx/compose/App.kt index b69140a22..0a9355b29 100644 --- a/compose/sample-android-compose/src/main/java/org/koin/sample/androidx/compose/App.kt +++ b/compose/sample-android-compose/src/main/java/org/koin/sample/androidx/compose/App.kt @@ -92,7 +92,7 @@ fun ViewModelComposable( @Composable fun SingleComposable( parentStatus: String = "- status -", - mySingle: MySingle = rememberKoinInject() + mySingle: MySingle = koinInject() ) { var created by remember { mutableStateOf(false) } @@ -108,7 +108,7 @@ fun SingleComposable( @Composable fun FactoryComposable( parentStatus: String = "- status -", - myFactory: MyFactory = rememberKoinInject { parametersOf("stable_status") } + myFactory: MyFactory = koinInject { parametersOf("stable_status") } ) { var created by remember { mutableStateOf(false) } rememberKoinModules(modules = { listOf(secondModule) }) diff --git a/compose/sample-android-compose/src/main/java/org/koin/sample/androidx/compose/MainActivity.kt b/compose/sample-android-compose/src/main/java/org/koin/sample/androidx/compose/MainActivity.kt index d007e116e..dea28e0de 100644 --- a/compose/sample-android-compose/src/main/java/org/koin/sample/androidx/compose/MainActivity.kt +++ b/compose/sample-android-compose/src/main/java/org/koin/sample/androidx/compose/MainActivity.kt @@ -19,7 +19,7 @@ class MainActivity : ScopeActivity() { assert(getKoin().getOrNull() == null) setContent { - KoinContext { + KoinAndroidContext { MaterialTheme { App() } diff --git a/compose/sample-android-compose/src/main/java/org/koin/sample/androidx/compose/MainApplication.kt b/compose/sample-android-compose/src/main/java/org/koin/sample/androidx/compose/MainApplication.kt index 71d5cab6b..f6a343875 100644 --- a/compose/sample-android-compose/src/main/java/org/koin/sample/androidx/compose/MainApplication.kt +++ b/compose/sample-android-compose/src/main/java/org/koin/sample/androidx/compose/MainApplication.kt @@ -13,7 +13,8 @@ class MainApplication : Application() { super.onCreate() startKoin { - androidLogger(Level.DEBUG) +// androidLogger(Level.DEBUG) + printLogger(Level.DEBUG) androidContext(this@MainApplication) modules(appModule) } diff --git a/compose/sample-android-compose/src/main/java/org/koin/sample/androidx/compose/SDKComposable.kt b/compose/sample-android-compose/src/main/java/org/koin/sample/androidx/compose/SDKComposable.kt index c3783e83b..4ba2e38bd 100644 --- a/compose/sample-android-compose/src/main/java/org/koin/sample/androidx/compose/SDKComposable.kt +++ b/compose/sample-android-compose/src/main/java/org/koin/sample/androidx/compose/SDKComposable.kt @@ -6,6 +6,7 @@ import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.remember import androidx.compose.runtime.setValue import org.koin.compose.KoinIsolatedContext +import org.koin.compose.koinInject import org.koin.compose.rememberKoinInject import org.koin.sample.androidx.compose.data.sdk.SDKData import org.koin.sample.androidx.compose.di.IsolatedContextSDK @@ -23,7 +24,7 @@ fun IsolatedSDKComposable( @Composable private fun SDKComposable( parentStatus: String = "- status -", - sdkData: SDKData = rememberKoinInject() + sdkData: SDKData = koinInject() ) { var created by remember { mutableStateOf(false) } diff --git a/compose/sample-desktop-compose/src/main/kotlin/org/koin/sample/compose/desktop/Main.kt b/compose/sample-desktop-compose/src/main/kotlin/org/koin/sample/compose/desktop/Main.kt index 9cc016159..3c5325f67 100644 --- a/compose/sample-desktop-compose/src/main/kotlin/org/koin/sample/compose/desktop/Main.kt +++ b/compose/sample-desktop-compose/src/main/kotlin/org/koin/sample/compose/desktop/Main.kt @@ -4,13 +4,18 @@ import androidx.compose.desktop.ui.tooling.preview.Preview import androidx.compose.material.Button import androidx.compose.material.MaterialTheme import androidx.compose.material.Text -import androidx.compose.runtime.* +import androidx.compose.runtime.Composable +import androidx.compose.runtime.getValue +import androidx.compose.runtime.mutableStateOf +import androidx.compose.runtime.remember +import androidx.compose.runtime.setValue import androidx.compose.ui.window.Window import androidx.compose.ui.window.application import org.koin.compose.KoinApplication import org.koin.compose.koinInject +import org.koin.core.logger.Level import org.koin.dsl.module -import java.util.* +import java.util.UUID class Myfactory { val id = UUID.randomUUID().toString() @@ -23,9 +28,12 @@ val mod = module { @Composable @Preview fun App() { - KoinApplication(application = { - modules(mod) - }) { + KoinApplication( + application = { + modules(mod) + printLogger(Level.DEBUG) + } + ) { var text by remember { mutableStateOf("Hello, World!") } val factory = koinInject() MaterialTheme { diff --git a/core/build.gradle b/core/build.gradle index c09e1753a..56fa5f95c 100644 --- a/core/build.gradle +++ b/core/build.gradle @@ -5,7 +5,6 @@ buildscript { mavenLocal() mavenCentral() google() - jcenter() } dependencies { // Kotlin @@ -28,7 +27,6 @@ allprojects { mavenLocal() mavenCentral() google() - jcenter() } group = 'io.insert-koin' @@ -42,4 +40,4 @@ allprojects { classifier = 'javadoc' from dokkaJavadoc } -} \ No newline at end of file +} diff --git a/core/gradle/versions.gradle b/core/gradle/versions.gradle index 94cd1d57b..d4703c8ee 100644 --- a/core/gradle/versions.gradle +++ b/core/gradle/versions.gradle @@ -1,13 +1,15 @@ ext { // Koin Versions - koin_version = '3.5.0' + koin_version = '3.5.3' // Kotlin - kotlin_version = '1.9.0' //TODO wait Compose for 1.9.10 or + + kotlin_version = '1.9.21' validator_version = '0.13.2' coroutines_version = "1.7.3" + stately_concurrency = "2.0.5" + // Dokka dokka_version = '1.8.10' diff --git a/core/koin-core-coroutines/build.gradle b/core/koin-core-coroutines/build.gradle index cdd6f913c..8b8cdc48c 100644 --- a/core/koin-core-coroutines/build.gradle +++ b/core/koin-core-coroutines/build.gradle @@ -36,9 +36,9 @@ kotlin { // mingwX64() // mingwX86() -// linuxX64() // linuxArm32Hfp() // linuxMips32() + linuxX64() sourceSets { commonMain { @@ -127,16 +127,16 @@ kotlin { compilations.main.source(sourceSets.darwinMain) compilations.test.source(sourceSets.nativeTest) } -// configure([ -// targets.linuxX64, + configure([ + targets.linuxX64, //// targets.linuxArm32Hfp, //// targets.linuxMips32, // targets.mingwX64, //// targets.mingwX86 -// ]) { -// compilations.main.source(sourceSets.otherMain) -// compilations.test.source(sourceSets.nativeTest) -// } + ]) { + compilations.main.source(sourceSets.otherMain) + compilations.test.source(sourceSets.nativeTest) + } } } diff --git a/core/koin-core/build.gradle b/core/koin-core/build.gradle index 6f95aa1db..b2a6619e4 100644 --- a/core/koin-core/build.gradle +++ b/core/koin-core/build.gradle @@ -25,21 +25,21 @@ kotlin { macosArm64() iosX64() iosArm64() -// iosArm32() iosSimulatorArm64() -// watchosArm32() + watchosArm32() watchosArm64() watchosSimulatorArm64() -// watchosX86() watchosX64() tvosArm64() tvosSimulatorArm64() tvosX64() - mingwX64() linuxX64() -// linuxArm64() + linuxArm64() + // Deprecated +// watchosX86() +// iosArm32() // mingwX86() // linuxArm32Hfp() // linuxMips32() @@ -77,7 +77,7 @@ kotlin { dependsOn commonMain dependencies { implementation 'org.jetbrains.kotlin:kotlin-stdlib-js' - implementation "co.touchlab:stately-concurrency:1.2.2" + implementation "co.touchlab:stately-concurrency:$stately_concurrency" } } @@ -91,7 +91,7 @@ kotlin { nativeMain { dependsOn commonMain dependencies { - implementation "co.touchlab:stately-concurrency:1.2.5" + implementation "co.touchlab:stately-concurrency:$stately_concurrency" } } @@ -114,7 +114,7 @@ kotlin { configure([ targets.macosX64, targets.macosArm64, -// targets.watchosArm32, + targets.watchosArm32, targets.watchosArm64, // targets.watchosX86, targets.watchosX64, @@ -132,9 +132,10 @@ kotlin { } configure([ targets.linuxX64, -// targets.linuxArm64, + targets.linuxArm64, targets.mingwX64, - + + // Deprecated // targets.linuxArm32Hfp, // targets.linuxMips32, // targets.mingwX86 diff --git a/core/koin-core/src/commonMain/kotlin/org/koin/core/registry/InstanceRegistry.kt b/core/koin-core/src/commonMain/kotlin/org/koin/core/registry/InstanceRegistry.kt index f5edeb1c7..c7c64b86a 100644 --- a/core/koin-core/src/commonMain/kotlin/org/koin/core/registry/InstanceRegistry.kt +++ b/core/koin-core/src/commonMain/kotlin/org/koin/core/registry/InstanceRegistry.kt @@ -52,17 +52,14 @@ class InstanceRegistry(val _koin: Koin) { private fun addAllEagerInstances(module: Module) { module.eagerInstances.forEach { factory -> -// if (eagerInstances.contains(factory)){ -// eagerInstances.remove(factory) -// } -// eagerInstances.add(factory) eagerInstances[factory.hashCode()] = factory } } internal fun createAllEagerInstances() { - createEagerInstances(eagerInstances.values) + val instances = arrayListOf(*eagerInstances.values.toTypedArray()) eagerInstances.clear() + createEagerInstances(instances) } private fun loadModule(module: Module, allowOverride: Boolean) { @@ -89,13 +86,9 @@ class InstanceRegistry(val _koin: Koin) { _instances[mapping] = factory } - private fun createEagerInstances(eagerInstances: Collection>) { - if (eagerInstances.isNotEmpty()) { - val defaultContext = InstanceContext(_koin.logger, _koin.scopeRegistry.rootScope) - eagerInstances.forEach { factory -> - factory.get(defaultContext) - } - } + private fun createEagerInstances(instances: Collection>) { + val defaultContext = InstanceContext(_koin.logger, _koin.scopeRegistry.rootScope) + instances.forEach { factory -> factory.get(defaultContext) } } internal fun resolveDefinition( diff --git a/core/koin-core/src/commonMain/kotlin/org/koin/core/registry/ScopeRegistry.kt b/core/koin-core/src/commonMain/kotlin/org/koin/core/registry/ScopeRegistry.kt index 45638b31b..7e91adb69 100644 --- a/core/koin-core/src/commonMain/kotlin/org/koin/core/registry/ScopeRegistry.kt +++ b/core/koin-core/src/commonMain/kotlin/org/koin/core/registry/ScopeRegistry.kt @@ -57,7 +57,7 @@ class ScopeRegistry(private val _koin: Koin) { internal fun createScope(scopeId: ScopeID, qualifier: Qualifier, source: Any? = null): Scope { _koin.logger.debug("|- (+) Scope - id:'$scopeId' q:$qualifier") if (!_scopeDefinitions.contains(qualifier)) { - _koin.logger.warn("| Scope '$qualifier' not defined. Creating it ...") + _koin.logger.debug("| Scope '$qualifier' not defined. Creating it ...") _scopeDefinitions.add(qualifier) } if (_scopes.contains(scopeId)) { diff --git a/docs/reference/koin-android/dsl-update.md b/docs/reference/koin-android/dsl-update.md index 4e9273144..1b7842677 100644 --- a/docs/reference/koin-android/dsl-update.md +++ b/docs/reference/koin-android/dsl-update.md @@ -8,7 +8,7 @@ Koin now offer a new kind of DSL keyword that allow you to target a class constr Check the new [Constructor DSL](../koin-core/dsl-update.md#constructor-dsl-since-32) section for more details. -For Android, this implies the following new constructore DSL Keyword: +For Android, this implies the following new constructor DSL Keyword: * `viewModelOf()` - equivalent of `viewModel { }` * `fragmentOf()` - equivalent of `fragment { }` diff --git a/docs/reference/koin-android/modules-android.md b/docs/reference/koin-android/modules-android.md index 1b44cbd91..8c2773dba 100644 --- a/docs/reference/koin-android/modules-android.md +++ b/docs/reference/koin-android/modules-android.md @@ -124,7 +124,7 @@ Notice that all modules will be included only once: `dataModule`, `domainModule` ## Reducing Startup time with background module loading -You can now declared "lazy" Koin module, to avoid trigger any pre allocation of resources and load them in background with Koin start. This can help avoid to block Android starting process, by passing lazy modules to be laoded in background. +You can now declared "lazy" Koin module, to avoid trigger any pre allocation of resources and load them in background with Koin start. This can help avoid to block Android starting process, by passing lazy modules to be loaded in background. - `lazyModule` - declare a Lazy Kotlin version of Koin Module - `Module.includes` - allow to include lazy Modules @@ -132,7 +132,7 @@ You can now declared "lazy" Koin module, to avoid trigger any pre allocation of - `Koin.waitAllStartJobs` - wait for start jobs to complete - `Koin.runOnKoinStarted` - run block code after start completion -A good example is always betetr to udnerstand: +A good example is always better to understand: ```kotlin @@ -154,7 +154,7 @@ startKoin { val koin = KoinPlatform.getKoin() -// wait for start completetion +// wait for start completion koin.waitAllStartJobs() // or run code after start diff --git a/docs/reference/koin-android/viewmodel.md b/docs/reference/koin-android/viewmodel.md index 0ef76d3ee..72a246ce9 100644 --- a/docs/reference/koin-android/viewmodel.md +++ b/docs/reference/koin-android/viewmodel.md @@ -191,7 +191,7 @@ ComponentActivity.viewModelForClass( ``` :::note -This function is still using `state: BundleDefinition`, but will comvert it to `CreationExtras` +This function is still using `state: BundleDefinition`, but will convert it to `CreationExtras` ::: Note that you can have access to the top level function, callable from anywhere: diff --git a/docs/reference/koin-compose/compose.md b/docs/reference/koin-compose/compose.md index 262c5c4f1..19b65fcd6 100644 --- a/docs/reference/koin-compose/compose.md +++ b/docs/reference/koin-compose/compose.md @@ -40,7 +40,7 @@ Difference between `KoinAndroidContext` and `KoinContext`: ### Compose Preview with Koin -The `KoinApplication` function is also interesting to start dedicated context for preview. This can be also used to helo with Compose preview: +The `KoinApplication` function is also interesting to start dedicated context for preview. This can be also used to help with Compose preview: ```kotlin @Composable @@ -66,8 +66,9 @@ For a module that declares a 'MyService' component: ```kotlin val androidModule = module { - single { MyService() } + // or constructor DSL + singleOf(::MyService) } ``` diff --git a/docs/reference/koin-compose/isolated-context.md b/docs/reference/koin-compose/isolated-context.md index f7bb7e3f0..384705694 100644 --- a/docs/reference/koin-compose/isolated-context.md +++ b/docs/reference/koin-compose/isolated-context.md @@ -6,7 +6,7 @@ With a Compose application, you can work the same way with an [isolated context] ## Define isolated context -First let's declare our isolated context holder, in order to store our isolated Koin isntance in memory. This can be done with a simple Object class like this. The `MyIsolatedKoinContext` class is holding our Koin instance: +First let's declare our isolated context holder, in order to store our isolated Koin instance in memory. This can be done with a simple Object class like this. The `MyIsolatedKoinContext` class is holding our Koin instance: ```kotlin object MyIsolatedKoinContext { diff --git a/docs/reference/koin-compose/multiplatform.md b/docs/reference/koin-compose/multiplatform.md index a08ff9878..d6a5f7267 100644 --- a/docs/reference/koin-compose/multiplatform.md +++ b/docs/reference/koin-compose/multiplatform.md @@ -34,7 +34,7 @@ fun App() { ### Compose Preview with Koin -The `KoinApplication` function is also interesting to start dedicated context for preview. This can be also used to helo with Compose preview: +The `KoinApplication` function is also interesting to start dedicated context for preview. This can be also used to help with Compose preview: ```kotlin @Composable diff --git a/docs/reference/koin-core/extension-manager.md b/docs/reference/koin-core/extension-manager.md index 0e401e5bd..6ee21907e 100644 --- a/docs/reference/koin-core/extension-manager.md +++ b/docs/reference/koin-core/extension-manager.md @@ -2,11 +2,11 @@ title: Extension Manager --- -Here is a brief description of `KoinExtension` manager, deidcated to add new features inside Koin framework. +Here is a brief description of `KoinExtension` manager, dedicated to add new features inside Koin framework. ## Defining an extension -A Koin extension consist in having a class inhereting from `KoinExtension` interface: +A Koin extension consist in having a class inheriting from `KoinExtension` interface: ```kotlin interface KoinExtension { diff --git a/docs/reference/koin-core/injection-parameters.md b/docs/reference/koin-core/injection-parameters.md index ddcfdb434..ef0dc04d1 100644 --- a/docs/reference/koin-core/injection-parameters.md +++ b/docs/reference/koin-core/injection-parameters.md @@ -57,7 +57,7 @@ val myModule = module { ## Resolving injected parameters in order -Instead of using `get()` to resovle a parameter, if you have several parameters of the same type you can use the index as follow `get(index)` (also same as `[ ]` operator): +Instead of using `get()` to resolve a parameter, if you have several parameters of the same type you can use the index as follow `get(index)` (also same as `[ ]` operator): ```kotlin class Presenter(val view : View) diff --git a/docs/reference/koin-core/modules.md b/docs/reference/koin-core/modules.md index 16baf60be..c84c5081d 100644 --- a/docs/reference/koin-core/modules.md +++ b/docs/reference/koin-core/modules.md @@ -99,7 +99,7 @@ This way, your share the definitions and avoid preallocate factories in a value. ## Overriding definition or module (before 3.1.0) -Koin won't allow you to redefinition an already existing definition (type,name,path ...). You will an an error if you try this: +Koin won't allow you to redefine an already existing definition (type,name,path ...). You will get an error if you try this: ```kotlin val myModuleA = module { @@ -253,12 +253,12 @@ startKoin { modules(featureModule1, featureModule2) } Notice that all modules will be included only once: `dataModule`, `domainModule`, `featureModule1`, `featureModule2`. :::info - If you have any compiling issue while including modules from the same file, either use `get()` Kotlin attribute operator on your module eitehr separate each moduel in files. See https://github.com/InsertKoinIO/koin/issues/1341 workaround + If you have any compiling issue while including modules from the same file, either use `get()` Kotlin attribute operator on your module either separate each module in files. See https://github.com/InsertKoinIO/koin/issues/1341 workaround ::: ## Lazy modules & background modules loading with Kotlin coroutines [Experimental] -You can now declared "lazy" Koin module, to avoid trigger any pre allocation of resources and load them in background with Koin start. +You can now declare "lazy" Koin module, to avoid trigger any pre allocation of resources and load them in background with Koin start. - `lazyModule` - declare a Lazy Kotlin version of Koin Module - `Module.includes` - allow to include lazy Modules @@ -266,7 +266,7 @@ You can now declared "lazy" Koin module, to avoid trigger any pre allocation of - `Koin.waitAllStartJobs` - wait for start jobs to complete - `Koin.runOnKoinStarted` - run block code after start completion -A good example is always betetr to udnerstand: +A good example is always better to understand: ```kotlin // Some lazy modules diff --git a/docs/reference/koin-ktor/ktor-isolated.md b/docs/reference/koin-ktor/ktor-isolated.md new file mode 100644 index 000000000..8312ba673 --- /dev/null +++ b/docs/reference/koin-ktor/ktor-isolated.md @@ -0,0 +1,27 @@ +--- +title: Ktor & Koin Isolated Context +--- + +The `koin-ktor` module is dedicated to bring dependency injection for Ktor. + + +## Isolated Koin Context Plugin + +To start an Isolated Koin container in Ktor, just install the `KoinIsolated` plugin like follow: + +```kotlin +fun Application.main() { + // Install Koin plugin + install(KoinIsolated) { + slf4jLogger() + modules(helloAppModule) + } +} +``` + +:::warning + By using an isolated Koin context you won't be able to use Koin outside of Ktor server instance (i.e: by using `GlobalContext` for example) +::: + + + diff --git a/docs/reference/koin-ktor/ktor.md b/docs/reference/koin-ktor/ktor.md index b3b09038d..5b8995728 100644 --- a/docs/reference/koin-ktor/ktor.md +++ b/docs/reference/koin-ktor/ktor.md @@ -1,5 +1,5 @@ --- -title: Ktor dependency injection with Koin +title: Dependency Injection in Ktor --- The `koin-ktor` module is dedicated to bring dependency injection for Ktor. @@ -10,7 +10,7 @@ To start a Koin container in Ktor, just install the `Koin` plugin like follow: ```kotlin fun Application.main() { - // Install Ktor features + // Install Koin install(Koin) { slf4jLogger() modules(helloAppModule) @@ -19,11 +19,6 @@ fun Application.main() { } ``` -:::note - Koin Ktor plugin uses isolated Koin context. You won't be able to start Koin outside of Ktor -::: - - ## Inject in Ktor Koin `inject()` and `get()` functions are available from `Application`,`Route`,`Routing` classes: diff --git a/docs/reference/koin-mp/kmp.md b/docs/reference/koin-mp/kmp.md index 31c2ff80d..d5600e7ad 100644 --- a/docs/reference/koin-mp/kmp.md +++ b/docs/reference/koin-mp/kmp.md @@ -141,4 +141,4 @@ struct ContentView: View { ### New Native Memory Management -Activate experiemental with root [gradle.properties](http://gradle.properties) properties: +Activate experimental with root [gradle.properties](http://gradle.properties) properties: diff --git a/docs/reference/koin-test/checkmodules.md b/docs/reference/koin-test/checkmodules.md index 0940ee23c..67e87494c 100644 --- a/docs/reference/koin-test/checkmodules.md +++ b/docs/reference/koin-test/checkmodules.md @@ -48,10 +48,10 @@ class NiaAppModuleCheck { Launch the JUnit test and you're done! ✅ -As you may see, we use the extraTypesparameter to list types used in the Koin configuration but not declared directly. This is the case for SavedStateHandle and WorkerParameters types, that are used as injected parameters. The Context is declared by androidContext() function at start. +As you may see, we use the extra Types parameter to list types used in the Koin configuration but not declared directly. This is the case for SavedStateHandle and WorkerParameters types, that are used as injected parameters. The Context is declared by androidContext() function at start. -The verify() API is ultra light to run and doesn't require any kind of mock/stubb to run on your configuration. +The verify() API is ultra light to run and doesn't require any kind of mock/stub to run on your configuration. ### Koin Dynamic Check - CheckModules() diff --git a/docs/resources/index.md b/docs/resources/index.md index 040cef63c..79e0feb14 100644 --- a/docs/resources/index.md +++ b/docs/resources/index.md @@ -10,7 +10,7 @@ title: Koin Developer Hub * [Opening Koin 1.0.0 Beta](https://medium.com/koin-developers/opening-the-koin-1-0-0-beta-version-99cb8be1c308) * [On the road to Koin 1.0](https://medium.com/koin-developers/on-the-road-to-koin-1-0-0-a624af55d07) * [Koin 0.9.2 — Maintenance fixes, new branding, roadmap for 1.0.0 & some other nice announces](https://medium.com/koin-developers/koin-0-9-2-maintenance-fixes-new-branding-roadmap-for-1-0-0-some-other-nice-announces-94f14648e4ad) -* [Koin 0.9.1 - Bug fixes & Improvments](https://medium.com/koin-developers/koin-0-9-1-bug-fixes-improvements-bug-fixes-d257cd2766fa) +* [Koin 0.9.1 - Bug fixes & Improvements](https://medium.com/koin-developers/koin-0-9-1-bug-fixes-improvements-bug-fixes-d257cd2766fa) * [Koin 0.9.0 - Getting close to stable](https://medium.com/koin-developers/koin-0-9-0-getting-close-to-stable-release-74df9bb9e181) * [Unlock your Android ViewModel power with Koin](https://medium.com/@giuliani.arnaud/unlock-your-android-viewmodel-power-with-koin-23eda8f493be) * [koin 0.8.2 Improvements bugfixes and crash fix](https://medium.com/koin-developers/koin-0-8-2-improvements-bugfixes-and-crash-fix-6b6809fc1dd2) diff --git a/docs/setup/koin.md b/docs/setup/koin.md index 97f3d35b1..66c3e572e 100644 --- a/docs/setup/koin.md +++ b/docs/setup/koin.md @@ -2,13 +2,13 @@ title: Koin --- -All you need to setup Koin in your project +All you need to setup Koin in your project ## Current Versions You can find all Koin packages on [maven central](https://search.maven.org/search?q=io.insert-koin). -Here are the current available versions: +Here are the currently available versions: | Project | Version | |----------|:-------------:| @@ -30,20 +30,42 @@ Here are the current available versions: ### Kotlin -Add `koin-core` dependency to your application: +Starting from 3.5.0 you can use BOM-version to manage all Koin library versions. When using the BOM in your app, you don't need to add any version to the Koin library dependencies themselves. When you update the BOM version, all the libraries that you're using are automatically updated to their new versions. -```groovy +Add `koin-bom` BOM and `koin-core` dependency to your application: +```kotlin +implementation(platform("io.insert-koin:koin-bom:$koin_version")) +implementation("io.insert-koin:koin-core") +``` +If you are using version catalogs: +```toml +[versions] +koin-bom = "x.x.x" +... + +[libraries] +koin-bom = { module = "io.insert-koin:koin-bom", version.ref = "di-koin" } +koin-core = { module = "io.insert-koin:koin-core" } +... +``` +```kotlin +dependencies { + implementation(libs.koin.bom) + implementation(libs.koin.core) +} +``` + +Or use an old way of specifying the exact dependency version for Koin: +```kotlin dependencies { - - compile "io.insert-koin:koin-core:$koin_version" + implementation("io.insert-koin:koin-core:$koin_version") } ``` -You are now ready to start Koin: +You are now ready to start Koin: ```kotlin fun main() { - startKoin { modules(...) } @@ -55,11 +77,11 @@ If you need testing capacity: ```groovy dependencies { // Koin Test features - testImplementation "io.insert-koin:koin-test:$koin_version" + testImplementation("io.insert-koin:koin-test:$koin_version") // Koin for JUnit 4 - testImplementation "io.insert-koin:koin-test-junit4:$koin_version" + testImplementation("io.insert-koin:koin-test-junit4:$koin_version") // Koin for JUnit 5 - testImplementation "io.insert-koin:koin-test-junit5:$koin_version" + testImplementation("io.insert-koin:koin-test-junit5:$koin_version") } ``` @@ -73,19 +95,18 @@ Add `koin-android` dependency to your Android application: ```groovy dependencies { - - implementation "io.insert-koin:koin-android:$koin_android_version" + implementation("io.insert-koin:koin-android:$koin_android_version") } ``` -You are now ready to start Koin in your `Application` class: +You are now ready to start Koin in your `Application` class: ```kotlin -class MainApplication : Application(){ +class MainApplication : Application() { override fun onCreate() { super.onCreate() - startKoin{ + startKoin { modules(appModule) } } @@ -97,11 +118,11 @@ If you need extra features, add the following needed package: ```groovy dependencies { // Java Compatibility - implementation "io.insert-koin:koin-android-compat:$koin_android_version" + implementation("io.insert-koin:koin-android-compat:$koin_android_version") // Jetpack WorkManager - implementation "io.insert-koin:koin-androidx-workmanager:$koin_android_version" + implementation("io.insert-koin:koin-androidx-workmanager:$koin_android_version") // Navigation Graph - implementation "io.insert-koin:koin-androidx-navigation:$koin_android_version" + implementation("io.insert-koin:koin-androidx-navigation:$koin_android_version") } ``` @@ -113,19 +134,18 @@ From now you can continue on Koin Tutorials to learn about using Koin: [Android ```groovy dependencies { - - implementation "io.insert-koin:koin-androidx-compose:$koin_android_compose_version" + implementation("io.insert-koin:koin-androidx-compose:$koin_android_compose_version") } ``` -You are now ready to start Koin in your `Application` class: +You are now ready to start Koin in your `Application` class: ```kotlin -class MainApplication : Application(){ +class MainApplication : Application() { override fun onCreate() { super.onCreate() - startKoin{ + startKoin { modules(appModule) } } @@ -143,8 +163,7 @@ Add `koin-core` dependency to your multiplatform application, for shared Kotlin ```groovy dependencies { - - compile "io.insert-koin:koin-core:$koin_version" + implementation("io.insert-koin:koin-core:$koin_version") } ``` @@ -154,18 +173,18 @@ From now you can continue on Koin Tutorials to learn about using Koin: [Kotlin M ### **Ktor** -Add `koin-ktor` dependency to your multiplatform application: +Add `koin-ktor` dependency to your Ktor application: ```groovy dependencies { // Koin for Ktor - implementation "io.insert-koin:koin-ktor:$koin_ktor" + implementation("io.insert-koin:koin-ktor:$koin_ktor") // SLF4J Logger - implementation "io.insert-koin:koin-logger-slf4j:$koin_ktor" + implementation("io.insert-koin:koin-logger-slf4j:$koin_ktor") } ``` -You are now ready to intall Koin feature into your Ktor application: +You are now ready to install Koin feature into your Ktor application: ```kotlin fun Application.main() { diff --git a/docs/setup/why.md b/docs/setup/why.md index f6fadbb09..3134d13ca 100644 --- a/docs/setup/why.md +++ b/docs/setup/why.md @@ -1,5 +1,5 @@ --- -title: Why koin? +title: Why Koin? --- Koin provides a easy and efficient way to incorporate dependency injection into any Kotlin application(Multiplatform, Android, backend ...) @@ -7,7 +7,7 @@ Koin provides a easy and efficient way to incorporate dependency injection into The goals of Koin are: - Simplify your Dependency Injection infrastructure with smart API - Kotlin DSL easy to read, easy to use, to let you write any kind of application -- Provides different kind of integration from Android ecoysystem, to more backend needs like Ktor +- Provides different kind of integration from Android ecosystem, to more backend needs like Ktor - Allow to be used with annotations ## Making your Kotlin development easy and productive @@ -17,16 +17,16 @@ Koin is a smart Kotlin dependency injection library to keep you focused on your ```kotlin class MyRepository() -class MyPresenterr(val repository : MyRepository) +class MyPresenter(val repository : MyRepository) // just declare it val myModule = module { - singleOf(::MyPresenterr) + singleOf(::MyPresenter) singleOf(::MyRepository) } ``` -Koin gives you simple tools and API to let you build, assemble Kotlin related technologies into your application and let you scale your business with easyness. +Koin gives you simple tools and API to let you build, assemble Kotlin related technologies into your application and let you scale your business with easiness. ```kotlin fun main() { @@ -48,14 +48,13 @@ class MyApplication : Application() { super.onCreate() startKoin { - modules(myModule) } } } ``` -Koin provides easy and powerfull API to retrieve your dependencies anywhere in Android components, with just using by inject() or by viewModel() +Koin provides easy and powerful API to retrieve your dependencies anywhere in Android components, with just using by inject() or by viewModel() ```kotlin class MyActivity : Application() { @@ -69,7 +68,7 @@ class MyActivity : Application() { Sharing code between mobile platforms is one of the major Kotlin Multiplatform use cases. With Kotlin Multiplatform Mobile, you can build cross-platform mobile applications and share common code between Android and iOS. -Koin provides multiplatform dependency injection and help build your components accross your native mobile applications, and web/backend applications. +Koin provides multiplatform dependency injection and help build your components across your native mobile applications, and web/backend applications. ## Performances and Productivity diff --git a/examples/androidx-samples/build.gradle b/examples/androidx-samples/build.gradle index 81e53e703..d13d3f491 100644 --- a/examples/androidx-samples/build.gradle +++ b/examples/androidx-samples/build.gradle @@ -2,7 +2,6 @@ buildscript { repositories { mavenLocal() mavenCentral() - jcenter() } dependencies { // classpath "io.insert-koin:koin-gradle-plugin:$koin_version" @@ -70,4 +69,4 @@ dependencies { implementation "io.insert-koin:koin-androidx-navigation" testImplementation "io.insert-koin:koin-test-junit4" testImplementation "io.insert-koin:koin-android-test" -} \ No newline at end of file +} diff --git a/examples/androidx-samples/src/main/java/org/koin/sample/sandbox/mvvm/MVVMActivity.kt b/examples/androidx-samples/src/main/java/org/koin/sample/sandbox/mvvm/MVVMActivity.kt index 7328a6bf4..9da57428c 100644 --- a/examples/androidx-samples/src/main/java/org/koin/sample/sandbox/mvvm/MVVMActivity.kt +++ b/examples/androidx-samples/src/main/java/org/koin/sample/sandbox/mvvm/MVVMActivity.kt @@ -8,7 +8,9 @@ import org.koin.android.ext.android.inject import org.koin.androidx.fragment.android.replace import org.koin.androidx.fragment.android.setupKoinFragmentFactory import org.koin.androidx.scope.ScopeActivity +import org.koin.androidx.viewmodel.ext.android.getViewModel import org.koin.androidx.viewmodel.ext.android.viewModel +import org.koin.androidx.viewmodel.ext.android.viewModelForClass import org.koin.core.parameter.parametersOf import org.koin.core.qualifier.named import org.koin.sample.sandbox.R @@ -21,7 +23,7 @@ import org.koin.sample.sandbox.utils.navigateTo class MVVMActivity : ScopeActivity(contentLayoutId = R.layout.mvvm_activity) { - val simpleViewModel: SimpleViewModel by viewModel { parametersOf(ID) } + lateinit var simpleViewModel: SimpleViewModel //by viewModel { parametersOf(ID) } val vm1: SimpleViewModel by viewModel(named("vm1")) { parametersOf("vm1") } val vm2: SimpleViewModel by viewModel(named("vm2")) { parametersOf("vm2") } @@ -58,6 +60,8 @@ class MVVMActivity : ScopeActivity(contentLayoutId = R.layout.mvvm_activity) { navigateTo(isRoot = true) } +// simpleViewModel = viewModelForClass(SimpleViewModel::class, owner = this).value + checks() } diff --git a/examples/androidx-samples/src/main/java/org/koin/sample/sandbox/mvvm/MVVMFragment.kt b/examples/androidx-samples/src/main/java/org/koin/sample/sandbox/mvvm/MVVMFragment.kt index 9e13f6649..a816ca157 100644 --- a/examples/androidx-samples/src/main/java/org/koin/sample/sandbox/mvvm/MVVMFragment.kt +++ b/examples/androidx-samples/src/main/java/org/koin/sample/sandbox/mvvm/MVVMFragment.kt @@ -48,11 +48,14 @@ class MVVMFragment(private val session: Session) : Fragment(R.layout.mvvm_fragme checkNotNull(session) assert(shared != simpleViewModel) - assert((requireActivity() as MVVMActivity).simpleViewModel == shared) + // TODO Handle shared isntance - out of Scope +// assert((requireActivity() as MVVMActivity).simpleViewModel == shared) +// assert((requireActivity() as MVVMActivity).savedVm == sharedSaved) + assert((requireActivity() as MVVMActivity).savedVm != saved) assert((requireActivity() as MVVMActivity).savedVm != saved2) assert(scopeVm.session.id == extScopeVm.session.id) - assert((requireActivity() as MVVMActivity).savedVm == sharedSaved) + val shared2 = getActivityViewModel { parametersOf(ID) } assert(shared == shared2) diff --git a/examples/coffee-maker/build.gradle b/examples/coffee-maker/build.gradle index db1238c55..195bf7093 100644 --- a/examples/coffee-maker/build.gradle +++ b/examples/coffee-maker/build.gradle @@ -2,7 +2,6 @@ buildscript { repositories { mavenLocal() mavenCentral() - jcenter() } dependencies { // classpath "io.insert-koin:koin-gradle-plugin:$koin_version" @@ -20,4 +19,4 @@ dependencies { testImplementation "io.insert-koin:koin-test-junit4:$koin_version" testImplementation "junit:junit:$junit_version" testImplementation "io.mockk:mockk:$mockk_version" -} \ No newline at end of file +} diff --git a/examples/jvm-perfs/build.gradle.kts b/examples/jvm-perfs/build.gradle.kts index 60b2daed0..8feae4e4e 100644 --- a/examples/jvm-perfs/build.gradle.kts +++ b/examples/jvm-perfs/build.gradle.kts @@ -17,7 +17,7 @@ tasks.getByName("compileKotlin" val jmhVersion = "1.36" //TODO get from existing version.gradle file -val koin_version = "3.5.0" +val koin_version = "3.5.2-RC1" val coroutines_version = "1.7.3" dependencies { diff --git a/ktor/examples/build.gradle b/ktor/examples/build.gradle index 2ce0d406f..a9372129e 100644 --- a/ktor/examples/build.gradle +++ b/ktor/examples/build.gradle @@ -4,7 +4,6 @@ buildscript { repositories { google() mavenCentral() - jcenter() } dependencies { // Kotlin @@ -22,6 +21,5 @@ allprojects { mavenLocal() mavenCentral() google() - jcenter() } -} \ No newline at end of file +} diff --git a/ktor/examples/multimodule-ktor/build.gradle b/ktor/examples/multimodule-ktor/build.gradle index e63440dd6..38a090e23 100644 --- a/ktor/examples/multimodule-ktor/build.gradle +++ b/ktor/examples/multimodule-ktor/build.gradle @@ -9,10 +9,9 @@ subprojects { repositories { mavenLocal() - jcenter() mavenCentral() maven { url "https://dl.bintray.com/kotlin/kotlinx" } maven { url "https://dl.bintray.com/kotlin/ktor" } } -} \ No newline at end of file +} diff --git a/ktor/gradle/versions.gradle b/ktor/gradle/versions.gradle index 917bf1beb..0bab3a234 100644 --- a/ktor/gradle/versions.gradle +++ b/ktor/gradle/versions.gradle @@ -1,6 +1,6 @@ ext { // Koin - koin_ktor_version = '3.5.1' + koin_ktor_version = '3.5.3' // Ktor - ktor_version = '2.3.3' + ktor_version = '2.3.7' } \ No newline at end of file diff --git a/ktor/koin-ktor/src/main/kotlin/org/koin/ktor/ext/ApplicationCallExt.kt b/ktor/koin-ktor/src/main/kotlin/org/koin/ktor/ext/ApplicationCallExt.kt index 75c54b80d..e429c5efe 100644 --- a/ktor/koin-ktor/src/main/kotlin/org/koin/ktor/ext/ApplicationCallExt.kt +++ b/ktor/koin-ktor/src/main/kotlin/org/koin/ktor/ext/ApplicationCallExt.kt @@ -19,10 +19,6 @@ import io.ktor.server.application.* import org.koin.core.Koin import org.koin.core.parameter.ParametersDefinition import org.koin.core.qualifier.Qualifier -import org.koin.core.scope.Scope -import org.koin.ktor.plugin.KOIN_ATTRIBUTE_KEY -import org.koin.ktor.plugin.KOIN_KEY -import org.koin.ktor.plugin.KOIN_SCOPE_ATTRIBUTE_KEY /** * Ktor Koin extensions for ApplicationCall class diff --git a/ktor/koin-ktor/src/main/kotlin/org/koin/ktor/plugin/KoinIsolatedContextPlugin.kt b/ktor/koin-ktor/src/main/kotlin/org/koin/ktor/plugin/KoinIsolatedContextPlugin.kt new file mode 100644 index 000000000..b0525fe7e --- /dev/null +++ b/ktor/koin-ktor/src/main/kotlin/org/koin/ktor/plugin/KoinIsolatedContextPlugin.kt @@ -0,0 +1,34 @@ +/* + * Copyright 2017-2023 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.koin.ktor.plugin + +import io.ktor.server.application.* +import org.koin.core.KoinApplication +import org.koin.core.annotation.KoinInternalApi + +/** + * @author Arnaud Giuliani + * + * Ktor Feature class. Allows Koin Isolatd Context to start using Ktor default install() method. + * + */ +@OptIn(KoinInternalApi::class) +val KoinIsolated = createApplicationPlugin(name = "Koin", createConfiguration = { KoinApplication.init() }) { + val koinApplication = setupKoinApplication() + setupMonitoring(koinApplication) + setupKoinScope(koinApplication) + koinApplication.koin.logger.info("Koin is using Ktor isolated context") +} diff --git a/ktor/koin-ktor/src/main/kotlin/org/koin/ktor/plugin/KoinPlugin.kt b/ktor/koin-ktor/src/main/kotlin/org/koin/ktor/plugin/KoinPlugin.kt index 3b5863b57..e8606957c 100644 --- a/ktor/koin-ktor/src/main/kotlin/org/koin/ktor/plugin/KoinPlugin.kt +++ b/ktor/koin-ktor/src/main/kotlin/org/koin/ktor/plugin/KoinPlugin.kt @@ -19,6 +19,7 @@ import io.ktor.server.application.* import io.ktor.server.application.hooks.* import io.ktor.util.* import org.koin.core.KoinApplication +import org.koin.core.context.startKoin import org.koin.core.scope.Scope import org.koin.dsl.KoinAppDeclaration @@ -28,16 +29,17 @@ import org.koin.dsl.KoinAppDeclaration * @author Victor Alenkov * @author Zak Henry * - * Ktor Feature class. Allows Koin Context to start using Ktor default install() method. + * Ktor Feature class. Allows Koin Standard Context to start using Ktor default install() method. * */ val Koin = createApplicationPlugin(name = "Koin", createConfiguration = { KoinApplication.init() }) { val koinApplication = setupKoinApplication() + startKoin(koinApplication) setupMonitoring(koinApplication) setupKoinScope(koinApplication) } -private fun PluginBuilder.setupKoinApplication(): KoinApplication { +internal fun PluginBuilder.setupKoinApplication(): KoinApplication { val koinApplication = pluginConfig koinApplication.createEagerInstances() application.setKoinApplication(koinApplication) @@ -48,7 +50,7 @@ fun Application.setKoinApplication(koinApplication: KoinApplication){ attributes.put(KOIN_ATTRIBUTE_KEY, koinApplication) } -private fun PluginBuilder.setupMonitoring(koinApplication: KoinApplication) { +internal fun PluginBuilder.setupMonitoring(koinApplication: KoinApplication) { val monitor = environment?.monitor monitor?.raise(KoinApplicationStarted, koinApplication) monitor?.subscribe(ApplicationStopping) { @@ -58,7 +60,7 @@ private fun PluginBuilder.setupMonitoring(koinApplication: Koin } } -private fun PluginBuilder.setupKoinScope(koinApplication: KoinApplication) { +internal fun PluginBuilder.setupKoinScope(koinApplication: KoinApplication) { // Scope Handling on(CallSetup) { call -> val scopeComponent = RequestScope(koinApplication.koin) diff --git a/ktor/koin-ktor/src/test/kotlin/org/koin/ktor/ext/KoinFeatureTest.kt b/ktor/koin-ktor/src/test/kotlin/org/koin/ktor/ext/KoinFeatureTest.kt index 9af916a60..72b814fd4 100644 --- a/ktor/koin-ktor/src/test/kotlin/org/koin/ktor/ext/KoinFeatureTest.kt +++ b/ktor/koin-ktor/src/test/kotlin/org/koin/ktor/ext/KoinFeatureTest.kt @@ -1,92 +1,64 @@ -//package org.koin.ktor.ext -// -//import io.ktor.application.* -//import io.ktor.server.testing.* -//import org.junit.Assert.* -//import org.junit.Ignore -//import org.junit.Test -//import org.koin.core.annotation.KoinReflectAPI -//import org.koin.core.context.GlobalContext -//import org.koin.core.context.loadKoinModules -//import org.koin.core.instance.newInstance -//import org.koin.core.parameter.emptyParametersHolder -//import org.koin.dsl.module -//import org.koin.dsl.single -// -///** -// * @author vinicius -// * @author Victor Alenkov -// * -// */ -//class Foo(val name: String = "") -//class Bar(val name: String = "") -//class Bar2(val name: String = "") -// -//@OptIn(KoinReflectAPI::class) -//class KoinFeatureTest { -// -// @Test -// fun `can install feature`() { -// val module = module { -// single { Foo("bar") } -// } -// withApplication { -// application.install(Koin) { -// modules(module) -// } -// val bean = GlobalContext.get().get() -// assertNotNull(bean) -// } -// } -// -// @Test -// fun `Koin does not contain modules`() { -// withApplication { -// assertNull(GlobalContext.getOrNull()) -// assertNull(application.featureOrNull(Koin)) -// -// application.install(Koin) -// assertNotNull(application.featureOrNull(Koin)) -// val koin = GlobalContext.getOrNull() -// assertNotNull(koin) -// requireNotNull(koin) -// -// assertNull(koin.getOrNull()) -// } -// } -// -// @Test -// fun `add a Koin module to an already running application`() { -// withApplication { -// application.install(Koin) -// val koin = application.getKoin() -// -// assertNull(koin.getOrNull()) -// -// application.featureOrNull(Koin)?.let { -// loadKoinModules(module { -// single() -// }) -// } -// assertNotNull(koin.getOrNull()) -// } -// } -// -// @Test -// fun `Using the koin extension`() { -// withApplication { -// assertNull(GlobalContext.getOrNull()) -// assertNull(application.featureOrNull(Koin)) -// -// application.koin { -// modules(module { -// single() -// }) -// } -// assertNotNull(application.getKoin().getOrNull()) -// } -// } -// +package org.koin.ktor.ext + +import io.ktor.server.application.* +import io.ktor.server.testing.* +import org.junit.After +import org.junit.Assert.* +import org.junit.Test +import org.koin.core.annotation.KoinReflectAPI +import org.koin.core.context.stopKoin +import org.koin.dsl.module +import org.koin.ktor.plugin.Koin +import org.koin.ktor.plugin.KoinIsolated +import org.koin.mp.KoinPlatform + +/** + * @author vinicius + * @author Victor Alenkov + * + */ +class Foo(val name: String = "") +class Bar(val name: String = "") +class Bar2(val name: String = "") + +@OptIn(KoinReflectAPI::class) +class KoinFeatureTest { + + @After + fun after(){ + stopKoin() + } + + @Test + fun `can install feature`() { + val module = module { + single { Foo("bar") } + } + withApplication { + application.install(Koin) { + modules(module) + } + val bean = KoinPlatform.getKoin().getOrNull() + assertNotNull(bean) + } + } + + @Test + fun `can install feature - isolated context`() { + val module = module { + single { Foo("bar") } + } + withApplication { + application.install(KoinIsolated) { + modules(module) + } + val bean1 = application.get() + assertNotNull(bean1) + val bean2 = runCatching { KoinPlatform.getKoin().getOrNull() }.getOrNull() + assertNull(bean2) + } + } + // @Test // fun `Using the koinModules extension`() { // withApplication { @@ -213,4 +185,4 @@ // } // assertEquals(4, c) // } -//} +} diff --git a/ktor/koin-ktor/src/test/kotlin/org/koin/ktor/ext/KoinPluginRunTest.kt b/ktor/koin-ktor/src/test/kotlin/org/koin/ktor/ext/KoinPluginRunTest.kt index 63d93aa30..f3cc95c97 100644 --- a/ktor/koin-ktor/src/test/kotlin/org/koin/ktor/ext/KoinPluginRunTest.kt +++ b/ktor/koin-ktor/src/test/kotlin/org/koin/ktor/ext/KoinPluginRunTest.kt @@ -28,9 +28,11 @@ import io.ktor.server.testing.* import kotlinx.coroutines.delay import kotlinx.coroutines.runBlocking import kotlinx.coroutines.withTimeout +import org.junit.Before import org.junit.Ignore import org.junit.Test import org.koin.core.context.startKoin +import org.koin.core.context.stopKoin import org.koin.core.logger.Level import org.koin.dsl.module import org.koin.ktor.plugin.Koin @@ -39,6 +41,11 @@ import kotlin.test.assertTrue class KoinPluginRunTest { + @Before + fun before(){ + stopKoin() + } + @Test fun `minimalistic app run`() { testMyApplication { @@ -50,7 +57,7 @@ class KoinPluginRunTest { } @Test - @Ignore + @Ignore // socket exception on GH fun `run outside context`() = runBlocking { var counter = 0 startKoin { diff --git a/plugins/build.gradle b/plugins/build.gradle index 53e40731b..84969f121 100644 --- a/plugins/build.gradle +++ b/plugins/build.gradle @@ -4,7 +4,7 @@ buildscript { repositories { google() - jcenter() + gradlePluginPortal() } dependencies { // Kotlin @@ -24,7 +24,6 @@ allprojects { repositories { mavenLocal() google() - jcenter() } group = 'io.insert-koin' @@ -38,4 +37,4 @@ allprojects { classifier = 'javadoc' from dokkaJavadoc } -} \ No newline at end of file +}