Skip to content

Commit

Permalink
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: allow creating custom qualifier annotations
Browse files Browse the repository at this point in the history
skyecodes committed Oct 3, 2024
1 parent d2b10cf commit 6058701
Showing 4 changed files with 56 additions and 10 deletions.
22 changes: 22 additions & 0 deletions docs/reference/koin-annotations/definitions.md
Original file line number Diff line number Diff line change
@@ -90,6 +90,28 @@ When resolving a dependency, just use the qualifier with `named` function:
val logger: LoggerDataSource by inject(named("InMemoryLogger"))
```

It is also possible to create custom qualifier annotations. Using the previous example:

```kotlin
@Named
annotation class InMemoryLogger

@Named
annotation class DatabaseLogger

@Single
@InMemoryLogger
class LoggerInMemoryDataSource : LoggerDataSource

@Single
@DatabaseLogger
class LoggerLocalDataSource(private val logDao: LogDao) : LoggerDataSource
```

```kotlin
val logger: LoggerDataSource by inject(named<InMemoryLogger>())
```

## Injected Parameters with @InjectedParam

You can tag a constructor member as "injected parameter", which means that the dependency will be passed in the graph when calling for resolution.
Original file line number Diff line number Diff line change
@@ -1,9 +1,6 @@
package org.koin.example.animal

import org.koin.core.annotation.ComponentScan
import org.koin.core.annotation.Factory
import org.koin.core.annotation.Module
import org.koin.core.annotation.Single
import org.koin.core.annotation.*
import kotlin.random.Random

public interface Animal
@@ -14,12 +11,28 @@ public class Dog : Animal
@Single(binds = [])
public class Cat : Animal

public class Bunny(public val color: String) : Animal

@Named
public annotation class WhiteBunny

@Qualifier
public annotation class BlackBunny

@Module
@ComponentScan
public class AnimalModule {

@Factory
public fun animal(cat: Cat, dog: Dog): Animal = if (randomBoolean()) cat else dog

@Single
@WhiteBunny
public fun whiteBunny(): Bunny = Bunny("White")

@Single
@BlackBunny
public fun blackBunny(): Bunny = Bunny("Black")

private fun randomBoolean(): Boolean = Random.nextBoolean()
}
15 changes: 11 additions & 4 deletions examples/other-ksp/src/test/kotlin/org.koin.example/TestModule.kt
Original file line number Diff line number Diff line change
@@ -2,13 +2,12 @@ package org.koin.example

import org.junit.Test
import org.koin.core.Koin
import org.koin.core.error.NoDefinitionFoundException
import org.koin.core.logger.Level
import org.koin.core.qualifier.named
import org.koin.core.qualifier.qualifier
import org.koin.dsl.koinApplication
import org.koin.example.animal.Animal
import org.koin.example.animal.AnimalModule
import org.koin.example.animal.Cat
import org.koin.example.animal.Dog
import org.koin.example.animal.*
import org.koin.example.`interface`.MyInterfaceExt
import org.koin.example.newmodule.*
import org.koin.example.newmodule.ComponentWithProps.Companion.DEFAULT_ID
@@ -19,6 +18,8 @@ import org.koin.example.scope.MyScopedInstance
import org.koin.example.scope.ScopeModule
import org.koin.ksp.generated.defaultModule
import org.koin.ksp.generated.module
import kotlin.test.assertEquals
import kotlin.test.assertFailsWith
import kotlin.test.assertTrue

class TestModule {
@@ -65,6 +66,12 @@ class TestModule {
assertTrue {
koin.get<MyScopeFactory>().msi == koin.get<MyScopeFactory>().msi
}

assertFailsWith(NoDefinitionFoundException::class) {
koin.get<Bunny>()
}

assertEquals("White", koin.get<Bunny>(qualifier<WhiteBunny>()).color)
}

private fun randomGetAnimal(koin: Koin): Animal {
Original file line number Diff line number Diff line change
@@ -73,16 +73,20 @@ fun List<KSValueArgument>.getQualifier(): KoinMetaData.Qualifier {
?: error("Qualifier annotation needs parameters: either type value or name")
}

private val qualifierAnnotations = listOf("Named", "Qualifier")
fun KSAnnotated.getQualifier(): String? {
val qualifierAnnotation = annotations.firstOrNull { a ->
val annotationName = a.shortName.asString()
(annotationName == "Named" || annotationName == "Qualifier")
if (annotationName in qualifierAnnotations) true
else (a.annotationType.resolve().declaration as KSClassDeclaration).annotations.any { a2 ->
a2.shortName.asString() in qualifierAnnotations
}
}
return qualifierAnnotation?.let {
when(it.shortName.asString()){
"${Named::class.simpleName}" -> it.arguments.getNamed().getValue()
"${Qualifier::class.simpleName}" -> it.arguments.getQualifier().getValue()
else -> null
else -> it.annotationType.resolve().declaration.qualifiedName?.asString()
}
}
}

0 comments on commit 6058701

Please sign in to comment.