STR:
ER: Instance is successfully declared
AR: Created scope already contains the instance
package com.test
import org.junit.Test
import org.koin.core.qualifier.named
import org.koin.dsl.koinApplication
import org.koin.dsl.module
class ScopeTest {
val baseUrl = "base_url"
val baseUrlKey = named("BASE_URL_KEY")
val scopeId = "user_scope"
val scopeKey = named("KEY")
val koin = koinApplication {
modules(
module {
scope(scopeKey) {
}
}
)
}.koin
@Test
fun `recreate a scope`() {
val scope = koin.createScope(scopeId, scopeKey)
scope.declare(baseUrl, baseUrlKey)
scope.close()
val scope2 = koin.createScope(scopeId, scopeKey)
scope2.declare(baseUrl, baseUrlKey)
}
}
org.koin.core.error.DefinitionOverrideException: Trying to override existing definition '[Single:'java.lang.String',qualifier:q:'BASE_URL_KEY',scope:q:'KEY']' with new definition typed 'class kotlin.String'
The issue was not observed on v2.0.1 but appeared after upgrading to 2.1.4
Having this issue on v 2.1.5. 馃槖

Thanks to @StanislavChumarin for investigation.
Not sure we need to deep copy the ScopeDefinition itself. This ScopeDefinition brings the Scope with all related definitions, no runtime things here.
But need to investigate 馃憤
Not sure we need to deep copy the ScopeDefinition itself. This
ScopeDefinitionbrings the Scope with all related definitions, no runtime things here.But need to investigate 馃憤
Maybe "deep copy" is not the accurate/right term here, but the idea is that a newly created scope should be only seeded with the compile time definitions (versus using the object directly as is). Scopes should not share among themselves the same seeded compile time definitions object, otherwise setting a new definition in runtime on a particular scope effectively sets it to all scopes (even future ones).
I'm having this problem as well - downgrading back to 2.0.1 for now fixes it.
This is particularly devastating to my use case, as it leads to leaking information across requests. I create a new Koin scope for each incoming request, and attach the per-request information to that scope, so that it can be dependency injected later on.
getKoin().createScope(this.uuid, REQUEST_SCOPE).use { scope ->
// Register external request and session objects
scope.declare(request)
scope.declare(session)
// Get the requested impl, which injects Request and Session
val impl: TImpl = scope.get(
clazz = implClass
)
// Use the impl
callback(impl)
}
Fixed in last 2.2.0-rc-4. Closing scope was not clearing any new declared extra definition.
@Test
fun `recreate a scope`() {
val baseUrl = "base_url"
val baseUrl2 = "base_url"
val baseUrlKey = named("BASE_URL_KEY")
val scopeId = "user_scope"
val scopeKey = named("KEY")
val koin = koinApplication {
modules(
module {
scope(scopeKey) {
scoped { Simple.ComponentA() }
}
}
)
}.koin
val scope = koin.createScope(scopeId, scopeKey)
scope.declare(baseUrl, baseUrlKey)
assertEquals(baseUrl,scope.get<String>(baseUrlKey))
scope.close()
val scope2 = koin.createScope(scopeId, scopeKey)
scope2.declare(baseUrl2, baseUrlKey)
assertEquals(baseUrl2,scope2.get<String>(baseUrlKey))
}
Most helpful comment
Thanks to @StanislavChumarin for investigation.