Hi! Does anyone faced issues with StandardScopeReg...
# kodein
a
Hi! Does anyone faced issues with StandardScopeRegistry producing InvalidMutabilityException when used in Scopes?
r
Hello. wow! that’s a weird one. • In which case do you had this issue ? JVM / Native ? • Which module of kodein are you using ? • do you have some code sample or reproducer ?
a
I got this one in the Native part. Using
Copy code
org.kodein.di:kodein-di-erased:6.5.0
Copy code
Uncaught Kotlin exception: kotlin.native.concurrent.InvalidMutabilityException: mutation attempt of frozen kotlin.collections.HashMap@1761508
        at 0   FitpuliShared                       0x0000000111e768e7 kfun:kotlin.Throwable.<init>(kotlin.String?)kotlin.Throwable + 87
        at 1   FitpuliShared                       0x0000000111e70305 kfun:kotlin.Exception.<init>(kotlin.String?)kotlin.Exception + 85
        at 2   FitpuliShared                       0x0000000111e6fee5 kfun:kotlin.RuntimeException.<init>(kotlin.String?)kotlin.RuntimeException + 85
        at 3   FitpuliShared                       0x0000000111ea3235 kfun:kotlin.native.concurrent.InvalidMutabilityException.<init>(kotlin.String)kotlin.native.concurrent.InvalidMutabilityException + 85
        at 4   FitpuliShared                       0x0000000111ea4a08 ThrowInvalidMutabilityException + 680
        at 5   FitpuliShared                       0x0000000112185048 MutationCheck + 104
        at 6   FitpuliShared                       0x0000000111e86c2d kfun:kotlin.collections.HashMap.<set-length>#internal + 77
        at 7   FitpuliShared                       0x0000000111e8b73d kfun:kotlin.collections.HashMap.addKey$stdlib(#GENERIC)ValueType + 1181
        at 8   FitpuliShared                       0x0000000111e87d4d kfun:kotlin.collections.HashMap.put(#GENERIC;#GENERIC)#GENERIC? + 317
        at 9   FitpuliShared                       0x0000000112037300 kfun:org.kodein.di.bindings.StandardScopeRegistry.getOrCreate(kotlin.Any;kotlin.Boolean;kotlin.Function0<org.kodein.di.bindings.Reference<kotlin.Any>>)kotlin.Any + 1408
        at 10  FitpuliShared                       0x000000011203c880 kfun:org.kodein.di.bindings.Singleton.getFactory$lambda-3#internal + 528
        at 11  FitpuliShared                       0x000000011203ccfb kfun:org.kodein.di.bindings.Singleton.$getFactory$lambda-3$FUNCTION_REFERENCE$59.invoke#internal + 203
        at 12  FitpuliShared                       0x000000011202eb2c kfun:org.kodein.di.KodeinContainer.provider$<anonymous>_1#internal + 188
        at 13  FitpuliShared                       0x000000011202ef27 kfun:org.kodein.di.KodeinContainer.$provider$<anonymous>_1$FUNCTION_REFERENCE$47.invoke#internal + 151
        at 14  FitpuliShared                       0x0000000112041c99 kfun:org.kodein.di.internal.DKodeinBaseImpl.Instance(org.kodein.di.TypeToken<#GENERIC_kotlin.Any>;kotlin.Any?)Generic + 1001
        at 15  FitpuliShared                       0x00000001120bbddd kfun:hu.fitpuli.mpp.data.di.useCaseModule$lambda-3$lambda-1#internal + 1165
        at 16  FitpuliShared                       0x00000001120bd6fd kfun:hu.fitpuli.mpp.data.di.$useCaseModule$lambda-3$lambda-1$FUNCTION_REFERENCE$4.invoke#internal + 173
        at 17  FitpuliShared                       0x000000011203c3ec kfun:org.kodein.di.bindings.Singleton.getFactory$lambda-3$lambda-2$lambda-1#internal + 524
        at 18  FitpuliShared                       0x000000011203cf0b kfun:org.kodein.di.bindings.Singleton.$getFactory$lambda-3$lambda-2$lambda-1$FUNCTION_REFERENCE$60.invoke#internal + 155
        at 19  FitpuliShared                       0x0000000112036573 kfun:org.kodein.di.bindings.SingletonReference.make(kotlin.Function0<#GENERIC_kotlin.Any>)Generic + 275
        at 20  FitpuliShared                       0x000000011203c5e8 kfun:org.kodein.di.bindings.Singleton.getFactory$lambda-3$lambda-2#internal + 376
        at 21  FitpuliShared                       0x000000011203d10b kfun:org.kodein.di.bindings.Singleton.$getFactory$lambda-3$lambda-2$FUNCTION_REFERENCE$61.invoke#internal + 155
        at 22  FitpuliShared                       0x00000001120371f7 kfun:org.kodein.di.bindings.StandardScopeRegistry.getOrCreate(kotlin.Any;kotlin.Boolean;kotlin.Function0<org.kodein.di.bindings.Reference<kotlin.Any>>)kotlin.Any + 1143
        at 23  FitpuliShared                       0x000000011203c880 kfun:org.kodein.di.bindings.Singleton.getFactory$lambda-3#internal + 528
        at 24  FitpuliShared                       0x000000011203ccfb kfun:org.kodein.di.bindings.Singleton.$getFactory$lambda-3$FUNCTION_REFERENCE$59.invoke#internal + 203
        at 25  FitpuliShared                       0x000000011202eb2c kfun:org.kodein.di.KodeinContainer.provider$<anonymous>_1#internal + 188
        at 26  FitpuliShared                       0x000000011202ef27 kfun:org.kodein.di.KodeinContainer.$provider$<anonymous>_1$FUNCTION_REFERENCE$47.invoke#internal + 151
        at 27  FitpuliShared                       0x0000000112041c99 kfun:org.kodein.di.internal.DKodeinBaseImpl.Instance(org.kodein.di.TypeToken<#GENERIC_kotlin.Any>;kotlin.Any?)Generic + 1001
        at 28  FitpuliShared                       0x00000001120d9df1 kfun:hu.fitpuli.mpp.FrameworkImpl.<init>$lambda-1$lambda-0#internal + 1217
        at 29  FitpuliShared                       0x00000001120db4c3 kfun:hu.fitpuli.mpp.FrameworkImpl.$<init>$lambda-1$lambda-0$FUNCTION_REFERENCE$1.invoke#internal + 195
(lldb)
I've created a custom scope:
Copy code
import co.touchlab.stately.collections.SharedHashMap
import hu.fitpuli.mpp.data.auth.User
import org.kodein.di.bindings.Scope
import org.kodein.di.bindings.ScopeRegistry
import org.kodein.di.bindings.StandardScopeRegistry
import kotlin.native.concurrent.ThreadLocal

@ThreadLocal
object UserSessionScope : Scope<User> {
    private val sessionRegistry: MutableMap<User, ScopeRegistry> = SharedHashMap()

    override fun getRegistry(context: User): ScopeRegistry = sessionRegistry.getOrPut(
            key = context,
            defaultValue = ::StandardScopeRegistry
    )
}
And when the framework tries to add a singleton to the scope I get this error:
r
Ok, we’ll look into it. Just, did you tried to syncrhonize the access to
sessionRegistry
in the
getRegistry()
method ? something like:
Copy code
override fun getRegistry(context: User): ScopeRegistry { 
            return synchronized(sessionRegistry) {
                sessionRegistry.getOrPut(
                    key = context,
                    defaultValue = ::StandardScopeRegistry
            )
        }
    }
Even not sure this is scope related. It might be the way you’ve declared your kodein container ? As in native companion and singleton are frozen by default… I’ll try to reproduce this on a simple project when I’ll have some time
a
Tried with syncronized but it didn't fixed the issue. Additional info, first I used HashMap for the sessionRegistry variable, in that case it crashed on the getOrPut in the getRegistry, with SharedHashMap, it crashes when it received the registry and tries to insert the first entry.
Found the source of the crash. I was using SharedHashMap to store the registries, wgich freezes the instances when put is called, resulting in a frozen StandardScopeRegistry.
r
Oh, ok. And what do you use instead to get the work done?
a
This is the currently working Scope:
Copy code
import org.kodein.di.bindings.Scope
import org.kodein.di.bindings.ScopeRegistry
import org.kodein.di.bindings.StandardScopeRegistry
import org.kodein.di.internal.maySynchronized

class UserSessionScope : Scope<User> {
    private val sessionRegistry: MutableMap<User, ScopeRegistry> = HashMap()

    override fun getRegistry(context: User): ScopeRegistry = maySynchronized(sessionRegistry) {
        sessionRegistry.getOrPut(
            key = context,
            defaultValue = ::StandardScopeRegistry
        )
    }
}
Plain old HashMap
r
And it doesn’t crash as you told before ?
a
Yes, as you sad it wasn't a scope related bug, it was related my Scope implementation. Thanks for pointing out! 🤗