Skip to content

TypeQualifiers are not correctly handled which causes trouble when using r8 #328

@BierDav

Description

@BierDav

Describe the bug

// Neither
object DatabaseIdentifier

@Single
@Qualifier(DatabaseIdentifier::class)
fun databaseIdentifier() = "default"

// Nor
@Qualifier
annotation class DatabaseCoroutineScope

@Single
@DatabaseCoroutineScope
fun coroutineScope() = CoroutineScope(Dispatchers.IO)

// Generate a TypeQualifier, but a StringQualifier with the fully qualified name, might change when using r8
single(qualifier=org.koin.core.qualifier.StringQualifier("data.db.DatabaseCoroutineScope")) { _ -> moduleInstance.coroutineScope()} bind(kotlinx.coroutines.CoroutineScope::class)
single(qualifier=org.koin.core.qualifier.StringQualifier("data.db.DatabaseIdentifier")) { _ -> moduleInstance.databaseIdentifier()} bind(kotlin.String::class)

To Reproduce
Steps to reproduce the behavior:

  1. Use koin-ksp-compiler and the sample above

Expected behavior
In both cases the compiler should ouput:

single(qualifier=org.koin.core.qualifier.TypeQualifier(data.db.DatabaseCoroutineScope::class)) { _ -> moduleInstance.coroutineScope()} bind(kotlinx.coroutines.CoroutineScope::class)
single(qualifier=org.koin.core.qualifier.TypeQualifier(data.db.DatabaseIdentifier::class)) { _ -> moduleInstance.databaseIdentifier()} bind(kotlin.String::class)

Koin project used and used version:

koin = "4.1.1"
koin-annotations = "2.3.1"

Note:
I already looked into the code a bit, and there seams to be a feature where koin serializes the arguments of the qualifier, which might block this seamingly easy fix. But I was wondering if there is even a way to access these qualifiers again at runtime? Because the implementation of qualifier<T>() just uses the java class name on Android:

actual fun getClassName(kClass: KClass<*>): String = kClass.java.name

And if there is no way to get value again at runtime I would consider this a preprogrammed hurdle for every developer the first time he tries to do so. I propose to actually remove this feature entirely, because in my opinion it is better to have less features with forseable behavior than features that are not documented and might cause unexpected behavior and confusions, because they have technical difficulties at the core.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions