Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Scan more than one component at the time #182

Open
wants to merge 8 commits into
base: 2.0.0
Choose a base branch
from
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,15 @@ import org.koin.sample.android.library.CommonModule
import org.koin.sample.androidx.repository.RepositoryModule
import org.koin.sample.clients.ClientModule

@Module(includes = [DataModule::class])
@ComponentScan("org.koin.sample.androidx.app")
class AppModule
//@Module(includes = [DataModule::class])
//@ComponentScan("org.koin.sample.androidx.app")
//class AppModule
//
//@Module(includes = [CommonModule::class, RepositoryModule::class])
//@ComponentScan("org.koin.sample.androidx.data")
//internal class DataModule


@Module(includes = [CommonModule::class, ClientModule::class, RepositoryModule::class])
@ComponentScan("org.koin.sample.androidx.data")
internal class DataModule
@ComponentScan("org.koin.sample.androidx.data", "org.koin.sample.androidx.app")
class AppModule
30 changes: 28 additions & 2 deletions examples/android-coffee-maker/src/test/java/AndroidModuleTest.kt
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ import org.koin.sample.androidx.app.ScopedStuff
import org.koin.sample.androidx.data.DataConsumer
import org.koin.sample.androidx.data.MyDataConsumer
import org.koin.sample.androidx.di.AppModule
import org.koin.sample.androidx.di.DataModule
//import org.koin.sample.androidx.di.DataModule
import org.koin.sample.androidx.repository.RepositoryModule

class AndroidModuleTest {
Expand All @@ -25,7 +25,7 @@ class AndroidModuleTest {
val koin = startKoin {
modules(
// defaultModule,
DataModule().module,
//DataModule().module,
RepositoryModule().module,
AppModule().module,
)
Expand All @@ -48,4 +48,30 @@ class AndroidModuleTest {

stopKoin()
}

@Test
fun run_all_modules_common() {
val koin = startKoin {
modules(
// defaultModule,
AppModule().module,
)
}.koin

val commonRepository = koin.get<CommonRepository>()
assert(!commonRepository.lazyParam.isInitialized())
assert(commonRepository.lazyParam != null)

val scope = koin.createScope<MyScope>()
scope.get<ScopedStuff>()

assert(koin.getOrNull<DataConsumer>() != null)
assert(koin.getOrNull<MyDataConsumer>() != null)

assert(koin.getOrNull<ExampleSingleton>() != null)


stopKoin()
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ class CoffeeAppModule {
}

@Module
@ComponentScan("org.koin.example.test")
@ComponentScan(value = ["org.koin.example.test"])
class CoffeeTesterModule {

@Single
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -202,13 +202,14 @@ annotation class PropertyValue(val value: String)
annotation class Module(val includes: Array<KClass<*>> = [], val createdAtStart: Boolean = false)

/**
* Gather definitions declared with Koin definition annotation
* Will scan in current package or with the explicit package name
* Gather definitions declared with Koin definition annotation.
* Will scan in current package or with the explicit packages names.
* For scan current package use empty value array or empty string.
*
* @param value: package to scan
* @param value: packages to scan
*/
@Target(AnnotationTarget.CLASS, AnnotationTarget.FIELD)
annotation class ComponentScan(val value: String = "")
annotation class ComponentScan(vararg val value: String = [])

/**
* Tag a dependency as already provided by Koin (like DSL declaration, or internals)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,14 @@ fun includedModules(annotation: KSAnnotation): List<KSDeclaration>? {
return declaredBindingsTypes?.map { it.declaration }
}

fun componentsScanValue(annotation: KSAnnotation): List<KoinMetaData.Module.ComponentScan>? {
val declaredBindingsTypes = annotation.arguments.firstOrNull { arg -> arg.name?.asString() == "value" }?.value as? List<String>?

val values = if (declaredBindingsTypes?.isEmpty() == true) listOf("") else declaredBindingsTypes

return values?.map { KoinMetaData.Module.ComponentScan(it.trim()) }
}

fun isCreatedAtStart(annotation: KSAnnotation): Boolean? {
return annotation.arguments.firstOrNull { it.name?.asString() == "createdAtStart" }?.value as? Boolean
}
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ sealed class KoinMetaData {
val definitions: MutableList<Definition> = mutableListOf(),
val externalDefinitions: MutableList<ExternalDefinition> = mutableListOf(),
val type: ModuleType = ModuleType.FIELD,
val componentScan: ComponentScan? = null,
val componentsScan: Set<ComponentScan> = emptySet(),
val includes: List<ModuleInclude>? = null,
val isCreatedAtStart: Boolean? = null,
val visibility: Visibility = Visibility.PUBLIC,
Expand All @@ -52,15 +52,16 @@ sealed class KoinMetaData {
data class ComponentScan(val packageName: String = "")

fun acceptDefinition(defPackageName: String): Boolean {
return when {
componentScan == null -> false
componentScan.packageName.isNotEmpty() -> defPackageName.contains(
componentScan.packageName,
ignoreCase = true
)

componentScan.packageName.isEmpty() -> defPackageName.contains(packageName, ignoreCase = true)
else -> false
return componentsScan.any { componentScan ->
when {
componentScan.packageName.isNotEmpty() -> defPackageName.contains(
componentScan.packageName,
ignoreCase = true
)

componentScan.packageName.isEmpty() -> defPackageName.contains(packageName, ignoreCase = true)
else -> false
}
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -124,7 +124,7 @@ class KoinMetaDataScanner(
val moduleList = hashMapOf<String, KoinMetaData.Module>()
val emptyScanList = arrayListOf<KoinMetaData.Module>()
forEach { module ->
module.componentScan?.let { scan ->
module.componentsScan.forEach { scan ->
when (scan.packageName) {
"" -> emptyScanList.add(module)
else -> if (moduleList.contains(scan.packageName)) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ class ModuleScanner(
val annotations = declaration.annotations
val includes = getIncludedModules(annotations)
val isCreatedAtStart = getIsCreatedAtStart(annotations)
val componentScan = getComponentScan(annotations)
val componentsScan = getComponentsScan(annotations)
val isExpect = declaration.isExpect
val isActual = declaration.isActual

Expand All @@ -46,7 +46,7 @@ class ModuleScanner(
packageName = modulePackage,
name = name,
type = type,
componentScan = componentScan,
componentsScan = componentsScan,
includes = includes.toModuleIncludes(),
isCreatedAtStart = isCreatedAtStart,
visibility = declaration.getVisibility(),
Expand Down Expand Up @@ -76,12 +76,9 @@ class ModuleScanner(
return module?.let { isCreatedAtStart(it) }
}

private fun getComponentScan(annotations: Sequence<KSAnnotation>): KoinMetaData.Module.ComponentScan? {
private fun getComponentsScan(annotations: Sequence<KSAnnotation>): Set<KoinMetaData.Module.ComponentScan> {
val componentScan = annotations.firstOrNull { it.shortName.asString() == "ComponentScan" }
return componentScan?.let { a ->
val value : String = a.arguments.firstOrNull { arg -> arg.name?.asString() == "value" }?.value as? String? ?: ""
KoinMetaData.Module.ComponentScan(value)
}
return componentScan?.let(::componentsScanValue)?.toSet() ?: emptySet()
}

private fun addFunctionDefinition(element: KSAnnotated): KoinMetaData.Definition? {
Expand Down