Skip to content

Commit

Permalink
[core] trying lazy params
Browse files Browse the repository at this point in the history
  • Loading branch information
Arnaud Giuliani committed Mar 5, 2018
1 parent b85f762 commit cff7ab6
Show file tree
Hide file tree
Showing 12 changed files with 154 additions and 50 deletions.
2 changes: 1 addition & 1 deletion common.gradle
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
ext {
// Koin
koin_version = '0.9.1-alpha-1'
koin_version = '0.9.1-alpha-2'

// Kotlin
kotlin_version = '1.2.30'
Expand Down
49 changes: 34 additions & 15 deletions koin-core/src/main/kotlin/org/koin/KoinContext.kt
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import org.koin.Koin.Companion.logger
import org.koin.core.bean.BeanDefinition
import org.koin.core.bean.BeanRegistry
import org.koin.core.instance.InstanceFactory
import org.koin.core.parameter.ParameterMap
import org.koin.core.property.PropertyRegistry
import org.koin.dsl.context.Parameters
import org.koin.error.ContextVisibilityException
Expand All @@ -20,47 +21,61 @@ import kotlin.reflect.KClass
*
* @author Arnaud GIULIANI
*/
class KoinContext(val beanRegistry: BeanRegistry,
val propertyResolver: PropertyRegistry,
val instanceFactory: InstanceFactory) : StandAloneKoinContext {
class KoinContext(
val beanRegistry: BeanRegistry,
val propertyResolver: PropertyRegistry,
val instanceFactory: InstanceFactory
) : StandAloneKoinContext {

/**
* call stack - bean definition resolution
*/
private val resolutionStack = Stack<StackItem>()
val resolutionStack = Stack<StackItem>()

var contextCallback: ContextCallback? = null

/**
* Retrieve a bean instance
*/
inline fun <reified T> get(name: String = "", parameters: ParameterMap = emptyMap()): T = if (name.isEmpty()) resolveByClass(parameters) else resolveByName(name, parameters)
inline fun <reified T> get(name: String = "", noinline parameters: ParameterMap = { emptyMap() }): T =
if (name.isEmpty()) resolveByClass(parameters) else resolveByName(name, parameters)

/**
* Resolve a dependency for its bean definition
* @param name bean definition name
*/
inline fun <reified T> resolveByName(name: String, parameters: ParameterMap): T = resolveInstance(T::class, parameters) { beanRegistry.searchByName(name) }
inline fun <reified T> resolveByName(name: String, noinline parameters: ParameterMap): T =
resolveInstance(T::class, parameters) { beanRegistry.searchByName(name) }

/**
* Resolve a dependency for its bean definition
* byt Its infered type
* byt Its inferred type
*/
inline fun <reified T> resolveByClass(parameters: ParameterMap): T = resolveByClass(T::class, parameters)
inline fun <reified T> resolveByClass(noinline parameters: ParameterMap): T =
resolveByClass(T::class, parameters)

/**
* Resolve a dependency for its bean definition
* byt its type
*/
inline fun <reified T> resolveByClass(clazz: KClass<*>, parameters: ParameterMap): T = resolveInstance(clazz, parameters) { beanRegistry.searchAll(clazz) }
inline fun <reified T> resolveByClass(clazz: KClass<*>, noinline parameters: ParameterMap): T =
resolveInstance(clazz, parameters) { beanRegistry.searchAll(clazz) }

/**
* Resolve a dependency for its bean definition
*/
fun <T> resolveInstance(clazz: KClass<*>, paramsValue: ParameterMap, definitionResolver: () -> List<BeanDefinition<*>>): T = synchronized(this) {
inline fun <T> resolveInstance(
clazz: KClass<*>,
noinline paramsValue: ParameterMap,
definitionResolver: () -> List<BeanDefinition<*>>
): T = synchronized(this) {
val clazzName = clazz.java.canonicalName
if (resolutionStack.any { it.isCompatibleWith(clazz) }) {
throw DependencyResolutionException("Cyclic call while resolving $clazzName. Definition is already in resolution in current call:\n\t${resolutionStack.joinToString("\n\t")}")
throw DependencyResolutionException(
"Cyclic call while resolving $clazzName. Definition is already in resolution in current call:\n\t${resolutionStack.joinToString(
"\n\t"
)}"
)
}

val lastInStack: BeanDefinition<*>? = if (resolutionStack.size > 0) resolutionStack.peek() else null
Expand All @@ -77,7 +92,11 @@ class KoinContext(val beanRegistry: BeanRegistry,
} else {
when {
candidates.isEmpty() -> throw NoBeanDefFoundException("No definition found to resolve type '$clazzName'. Check your module definition")
else -> throw DependencyResolutionException("Multiple definitions found to resolve type '$clazzName' - Koin can't choose between :\n\t${candidates.joinToString("\n\t")}\n\tCheck your modules definition or use name attribute to resolve components.")
else -> throw DependencyResolutionException(
"Multiple definitions found to resolve type '$clazzName' - Koin can't choose between :\n\t${candidates.joinToString(
"\n\t"
)}\n\tCheck your modules definition or use name attribute to resolve components."
)
}
}

Expand Down Expand Up @@ -138,7 +157,8 @@ class KoinContext(val beanRegistry: BeanRegistry,
* @param key - property key
* @param defaultValue - default value if property is not found
*/
inline fun <reified T> getProperty(key: String, defaultValue: T): T = propertyResolver.getProperty(key, defaultValue)
inline fun <reified T> getProperty(key: String, defaultValue: T): T =
propertyResolver.getProperty(key, defaultValue)

/**
* Set a property
Expand Down Expand Up @@ -179,5 +199,4 @@ interface ContextCallback {
fun onContextReleased(contextName: String)
}

typealias ParameterMap = Map<String, Any>
typealias StackItem = BeanDefinition<*>
typealias StackItem = BeanDefinition<*>
13 changes: 13 additions & 0 deletions koin-core/src/main/kotlin/org/koin/core/parameter/Parameters.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package org.koin.core.parameter


/**
* Parameter type to be passsed to BeanDefinition
*/
typealias ParameterMap = () -> Map<String, Any>

/**
* helper to write map of Values into ParameterMap
*/
fun valuesOf(pair: Pair<String, Any>): () -> Map<String,Any> =
{ mapOf(pair) }
17 changes: 12 additions & 5 deletions koin-core/src/main/kotlin/org/koin/dsl/context/Context.kt
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
package org.koin.dsl.context

import org.koin.KoinContext
import org.koin.ParameterMap
import org.koin.core.bean.BeanDefinition
import org.koin.core.bean.Definition
import org.koin.core.parameter.ParameterMap
import org.koin.core.scope.Scope

/**
Expand Down Expand Up @@ -40,7 +40,11 @@ class Context(val name: String = Scope.ROOT, val koinContext: KoinContext) {
* @param isSingleton
*/
@Deprecated("use `bean` (for singleton instances) or `factory` (for factory instances)")
inline fun <reified T : Any> provide(name: String = "", isSingleton: Boolean = true, noinline definition: Definition<T>): BeanDefinition<T> {
inline fun <reified T : Any> provide(
name: String = "",
isSingleton: Boolean = true,
noinline definition: Definition<T>
): BeanDefinition<T> {
val beanDefinition = BeanDefinition(name, T::class, isSingleton = isSingleton, definition = definition)
definitions += beanDefinition
return beanDefinition
Expand All @@ -67,13 +71,15 @@ class Context(val name: String = Scope.ROOT, val koinContext: KoinContext) {
/**
* Resolve a component
*/
inline fun <reified T : Any> get(parameters: ParameterMap = emptyMap()): T = koinContext.resolveByClass(parameters)
inline fun <reified T : Any> get(noinline parameters: ParameterMap = { emptyMap() }): T =
koinContext.resolveByClass(parameters)

/**
* Resolve a component
* @param name : component name
*/
inline fun <reified T : Any> get(name: String, parameters: ParameterMap = emptyMap()): T = koinContext.resolveByName(name, parameters)
inline fun <reified T : Any> get(name: String, noinline parameters: ParameterMap = { emptyMap() }): T =
koinContext.resolveByName(name, parameters)

/**
* Retrieve a property
Expand All @@ -86,7 +92,8 @@ class Context(val name: String = Scope.ROOT, val koinContext: KoinContext) {
* @param key - property key
* @param defaultValue - default value
*/
inline fun <reified T> getProperty(key: String, defaultValue: T) = koinContext.propertyResolver.getProperty(key, defaultValue)
inline fun <reified T> getProperty(key: String, defaultValue: T) =
koinContext.propertyResolver.getProperty(key, defaultValue)

// String display
override fun toString(): String = "Context[$name]"
Expand Down
10 changes: 6 additions & 4 deletions koin-core/src/main/kotlin/org/koin/dsl/context/Parameters.kt
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
package org.koin.dsl.context

import org.koin.ParameterMap
import org.koin.core.parameter.ParameterMap

/**
* Provide a parameter
Expand All @@ -23,14 +23,16 @@ interface ParametersProvider {
/**
* Parameters holder
*/
data class Parameters(override val values: ParameterMap = emptyMap()) : ParametersProvider {
data class Parameters(override inline val values: ParameterMap = { emptyMap() }) : ParametersProvider {

private val unfoldValues by lazy { values() }

@Suppress("UNCHECKED_CAST")
override fun <T> getOrNUll(key: String): T? {
return values[key] as? T
return unfoldValues[key] as? T
}

@Suppress("UNCHECKED_CAST")
override operator fun <T> get(key: String): T = values[key] as T
override operator fun <T> get(key: String): T = unfoldValues[key] as T

}
20 changes: 13 additions & 7 deletions koin-core/src/main/kotlin/org/koin/standalone/KoinComponent.kt
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
package org.koin.standalone

import org.koin.KoinContext
import org.koin.ParameterMap
import org.koin.core.parameter.ParameterMap

/**
* Koin component
Expand All @@ -12,14 +12,16 @@ interface KoinComponent
* inject lazily given dependency for KoinComponent
* @param name - bean name / optional
*/
inline fun <reified T> KoinComponent.inject(name: String = "", parameters: ParameterMap = emptyMap()) = kotlin.lazy { (StandAloneContext.koinContext as KoinContext).get<T>(name, parameters) }
inline fun <reified T> KoinComponent.inject(name: String = "", noinline parameters: ParameterMap = { emptyMap() }) =
kotlin.lazy { (StandAloneContext.koinContext as KoinContext).get<T>(name, parameters) }

/**
* inject lazily given property for KoinComponent
* @param key - key property
* throw MissingPropertyException if property is not found
*/
inline fun <reified T> KoinComponent.property(key: String) = kotlin.lazy { (StandAloneContext.koinContext as KoinContext).getProperty<T>(key) }
inline fun <reified T> KoinComponent.property(key: String) =
kotlin.lazy { (StandAloneContext.koinContext as KoinContext).getProperty<T>(key) }

/**
* inject lazily given property for KoinComponent
Expand All @@ -29,7 +31,8 @@ inline fun <reified T> KoinComponent.property(key: String) = kotlin.lazy { (Stan
* @param defaultValue - default value if property is missing
*
*/
inline fun <reified T> KoinComponent.property(key: String, defaultValue: T) = kotlin.lazy { (StandAloneContext.koinContext as KoinContext).getProperty(key, defaultValue) }
inline fun <reified T> KoinComponent.property(key: String, defaultValue: T) =
kotlin.lazy { (StandAloneContext.koinContext as KoinContext).getProperty(key, defaultValue) }


/**
Expand All @@ -41,14 +44,16 @@ private fun context() = (StandAloneContext.koinContext as KoinContext)
* Retrieve given dependency for KoinComponent
* @param name - bean name / optional
*/
inline fun <reified T> KoinComponent.get(name: String = "", parameters: ParameterMap = emptyMap()) = (StandAloneContext.koinContext as KoinContext).get<T>(name, parameters)
inline fun <reified T> KoinComponent.get(name: String = "", noinline parameters: ParameterMap = { emptyMap() }) =
(StandAloneContext.koinContext as KoinContext).get<T>(name, parameters)

/**
* Retrieve given property for KoinComponent
* @param key - key property
* throw MissingPropertyException if property is not found
*/
inline fun <reified T> KoinComponent.getProperty(key: String) = (StandAloneContext.koinContext as KoinContext).getProperty<T>(key)
inline fun <reified T> KoinComponent.getProperty(key: String) =
(StandAloneContext.koinContext as KoinContext).getProperty<T>(key)

/**
* Retrieve given property for KoinComponent
Expand All @@ -58,7 +63,8 @@ inline fun <reified T> KoinComponent.getProperty(key: String) = (StandAloneConte
* @param defaultValue - default value if property is missing
*
*/
inline fun <reified T> KoinComponent.getProperty(key: String, defaultValue: T) = (StandAloneContext.koinContext as KoinContext).getProperty(key, defaultValue)
inline fun <reified T> KoinComponent.getProperty(key: String, defaultValue: T) =
(StandAloneContext.koinContext as KoinContext).getProperty(key, defaultValue)

/**
* set a property
Expand Down
20 changes: 13 additions & 7 deletions koin-ktor/src/main/kotlin/org/koin/ktor/ext/KtorApplicationExt.kt
Original file line number Diff line number Diff line change
Expand Up @@ -2,21 +2,23 @@ package org.koin.ktor.ext

import io.ktor.application.Application
import org.koin.KoinContext
import org.koin.ParameterMap
import org.koin.core.parameter.ParameterMap
import org.koin.standalone.StandAloneContext

/**
* inject lazily given dependency
* @param name - bean name / optional
*/
inline fun <reified T> Application.inject(name: String = "", parameters: ParameterMap = emptyMap()) = lazy { (StandAloneContext.koinContext as KoinContext).get<T>(name, parameters) }
inline fun <reified T> Application.inject(name: String = "", noinline parameters: ParameterMap = { emptyMap() }) =
lazy { (StandAloneContext.koinContext as KoinContext).get<T>(name, parameters) }

/**
* lazy inject given property
* @param key - key property
* throw MissingPropertyException if property is not found
*/
inline fun <reified T> Application.property(key: String) = lazy { (StandAloneContext.koinContext as KoinContext).getProperty<T>(key) }
inline fun <reified T> Application.property(key: String) =
lazy { (StandAloneContext.koinContext as KoinContext).getProperty<T>(key) }

/**
* lazy inject given property
Expand All @@ -26,20 +28,23 @@ inline fun <reified T> Application.property(key: String) = lazy { (StandAloneCon
* @param defaultValue - default value if property is missing
*
*/
inline fun <reified T> Application.property(key: String, defaultValue: T) = lazy { (StandAloneContext.koinContext as KoinContext).getProperty(key, defaultValue) }
inline fun <reified T> Application.property(key: String, defaultValue: T) =
lazy { (StandAloneContext.koinContext as KoinContext).getProperty(key, defaultValue) }

/**
* Retrieve given dependency for KoinComponent
* @param name - bean name / optional
*/
inline fun <reified T> Application.get(name: String = "", parameters: ParameterMap = emptyMap()) = (StandAloneContext.koinContext as KoinContext).get<T>(name, parameters)
inline fun <reified T> Application.get(name: String = "", noinline parameters: ParameterMap = { emptyMap() }) =
(StandAloneContext.koinContext as KoinContext).get<T>(name, parameters)

/**
* Retrieve given property for KoinComponent
* @param key - key property
* throw MissingPropertyException if property is not found
*/
inline fun <reified T> Application.getProperty(key: String) = (StandAloneContext.koinContext as KoinContext).getProperty<T>(key)
inline fun <reified T> Application.getProperty(key: String) =
(StandAloneContext.koinContext as KoinContext).getProperty<T>(key)

/**
* Retrieve given property for KoinComponent
Expand All @@ -49,7 +54,8 @@ inline fun <reified T> Application.getProperty(key: String) = (StandAloneContext
* @param defaultValue - default value if property is missing
*
*/
inline fun <reified T> Application.getProperty(key: String, defaultValue: T) = (StandAloneContext.koinContext as KoinContext).getProperty(key, defaultValue)
inline fun <reified T> Application.getProperty(key: String, defaultValue: T) =
(StandAloneContext.koinContext as KoinContext).getProperty(key, defaultValue)


/**
Expand Down
4 changes: 2 additions & 2 deletions koin-test/src/main/kotlin/org/koin/test/KoinTest.kt
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ package org.koin.test
import org.junit.After
import org.koin.Koin
import org.koin.KoinContext
import org.koin.ParameterMap
import org.koin.core.parameter.ParameterMap
import org.koin.standalone.KoinComponent
import org.koin.standalone.StandAloneContext
import org.koin.standalone.StandAloneContext.closeKoin
Expand All @@ -16,7 +16,7 @@ interface KoinTest : KoinComponent
/**
* Make a Dry Run - Test if each definition is injectable
*/
fun KoinTest.dryRun(defaultParameters: ParameterMap = emptyMap()) {
fun KoinTest.dryRun(defaultParameters: ParameterMap = { emptyMap() }) {
(StandAloneContext.koinContext as KoinContext).dryRun(defaultParameters)
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package org.koin.test.core

import org.junit.Assert
import org.junit.Test
import org.koin.core.parameter.valuesOf
import org.koin.dsl.module.applicationContext
import org.koin.standalone.KoinComponent
import org.koin.standalone.StandAloneContext.startKoin
Expand All @@ -19,11 +20,7 @@ class ParametersInstanceTest : AutoCloseKoinTest() {
class ComponentA(val componentB: ComponentB)
class ComponentB : KoinComponent {

init {
println("Ctor Component1")
}

val compA: ComponentA by inject(parameters = mapOf("this" to this))
val compA: ComponentA by inject(parameters = valuesOf("this" to this))
}

@Test
Expand Down
Loading

0 comments on commit cff7ab6

Please sign in to comment.