From c9a22e601dd8d82f618ddb28745c16f4a373f53e Mon Sep 17 00:00:00 2001 From: "shen.xudong" Date: Fri, 10 Apr 2020 19:36:02 +0800 Subject: [PATCH 1/2] support declare a component definition with primary type --- .../src/main/kotlin/org/koin/core/Koin.kt | 3 +- .../koin/core/error/BadDefinitionException.kt | 3 ++ .../main/kotlin/org/koin/core/scope/Scope.kt | 4 +- .../org/koin/core/scope/ScopeDefinition.kt | 6 ++- .../java/org/koin/core/DeclareInstanceTest.kt | 47 ++++++++++++++++++- .../main/kotlin/org/koin/test/mock/Declare.kt | 2 +- .../kotlin/org/koin/test/mock/DeclareMock.kt | 2 +- 7 files changed, 60 insertions(+), 7 deletions(-) create mode 100644 koin-projects/koin-core/src/main/kotlin/org/koin/core/error/BadDefinitionException.kt diff --git a/koin-projects/koin-core/src/main/kotlin/org/koin/core/Koin.kt b/koin-projects/koin-core/src/main/kotlin/org/koin/core/Koin.kt index 2005ed032..2545799fa 100644 --- a/koin-projects/koin-core/src/main/kotlin/org/koin/core/Koin.kt +++ b/koin-projects/koin-core/src/main/kotlin/org/koin/core/Koin.kt @@ -139,12 +139,13 @@ class Koin { */ inline fun declare( instance: T, + clazz: KClass<*> = instance::class, qualifier: Qualifier? = null, secondaryTypes: List> = emptyList(), override: Boolean = false ) { val firstType = listOf(T::class) - _scopeRegistry.rootScope.declare(instance, qualifier, firstType + secondaryTypes, override) + _scopeRegistry.rootScope.declare(instance, clazz, qualifier, firstType + secondaryTypes, override) } /** diff --git a/koin-projects/koin-core/src/main/kotlin/org/koin/core/error/BadDefinitionException.kt b/koin-projects/koin-core/src/main/kotlin/org/koin/core/error/BadDefinitionException.kt new file mode 100644 index 000000000..6fcb115d2 --- /dev/null +++ b/koin-projects/koin-core/src/main/kotlin/org/koin/core/error/BadDefinitionException.kt @@ -0,0 +1,3 @@ +package org.koin.core.error + +class BadDefinitionException(str: String) : Exception(str) \ No newline at end of file diff --git a/koin-projects/koin-core/src/main/kotlin/org/koin/core/scope/Scope.kt b/koin-projects/koin-core/src/main/kotlin/org/koin/core/scope/Scope.kt index 685cbe85e..6a004b7c7 100644 --- a/koin-projects/koin-core/src/main/kotlin/org/koin/core/scope/Scope.kt +++ b/koin-projects/koin-core/src/main/kotlin/org/koin/core/scope/Scope.kt @@ -260,17 +260,19 @@ data class Scope( * (single definition of th current scope is root) * * @param instance The instance you're declaring. + * @param clazz The primary type for this declaration * @param qualifier Qualifier for this declaration * @param secondaryTypes List of secondary bound types * @param override Allows to override a previous declaration of the same type (default to false). */ fun declare( instance: T, + clazz: KClass<*> = instance::class, qualifier: Qualifier? = null, secondaryTypes: List>? = null, override: Boolean = false ) = synchronized(this) { - val definition = _scopeDefinition.saveNewDefinition(instance, qualifier, secondaryTypes, override) + val definition = _scopeDefinition.saveNewDefinition(instance, clazz, qualifier, secondaryTypes, override) _instanceRegistry.saveDefinition(definition, override = true) } diff --git a/koin-projects/koin-core/src/main/kotlin/org/koin/core/scope/ScopeDefinition.kt b/koin-projects/koin-core/src/main/kotlin/org/koin/core/scope/ScopeDefinition.kt index e946b41e3..3460e2c51 100644 --- a/koin-projects/koin-core/src/main/kotlin/org/koin/core/scope/ScopeDefinition.kt +++ b/koin-projects/koin-core/src/main/kotlin/org/koin/core/scope/ScopeDefinition.kt @@ -3,6 +3,7 @@ package org.koin.core.scope import org.koin.core.definition.BeanDefinition import org.koin.core.definition.Definitions import org.koin.core.definition.Options +import org.koin.core.error.BadDefinitionException import org.koin.core.error.DefinitionOverrideException import org.koin.core.qualifier.Qualifier import org.koin.core.qualifier._q @@ -36,11 +37,14 @@ class ScopeDefinition(val qualifier: Qualifier, val isRoot: Boolean = false, pri fun saveNewDefinition( instance: T, + clazz: KClass<*> = instance::class, qualifier: Qualifier? = null, secondaryTypes: List>? = null, override: Boolean = false ): BeanDefinition { - val clazz = instance::class + if (!clazz.isInstance(instance)) { + throw BadDefinitionException("Primary type '$clazz' should be or supertype of '${instance::class}'") + } val found: BeanDefinition<*>? = definitions.firstOrNull { def -> def.`is`(clazz, qualifier, this) } if (found != null) { diff --git a/koin-projects/koin-core/src/test/java/org/koin/core/DeclareInstanceTest.kt b/koin-projects/koin-core/src/test/java/org/koin/core/DeclareInstanceTest.kt index c2199e121..40595f9b4 100644 --- a/koin-projects/koin-core/src/test/java/org/koin/core/DeclareInstanceTest.kt +++ b/koin-projects/koin-core/src/test/java/org/koin/core/DeclareInstanceTest.kt @@ -4,6 +4,7 @@ import org.junit.Assert.* import org.junit.Ignore import org.junit.Test import org.koin.Simple +import org.koin.core.error.BadDefinitionException import org.koin.core.error.DefinitionOverrideException import org.koin.core.error.NoBeanDefFoundException import org.koin.core.logger.Level @@ -96,7 +97,7 @@ class DeclareInstanceTest { val a = Simple.ComponentA() - koin.declare(a, named("another_a")) + koin.declare(a, qualifier = named("another_a")) assertEquals(a, koin.get(named("another_a"))) assertNotEquals(a, koin.get()) @@ -115,7 +116,7 @@ class DeclareInstanceTest { val a = Simple.ComponentA() - koin.declare(a, named("another_a"), override = true) + koin.declare(a, qualifier = named("another_a"), override = true) assertEquals(a, koin.get(named("another_a"))) assertNotEquals(a, koin.get()) @@ -193,6 +194,48 @@ class DeclareInstanceTest { assertEquals(a, session1.get().a) } + @Test + fun `can declare a scoped on the fly with primary type`() { + + val koin = koinApplication { + printLogger() + modules(module { + scope(named("Session")) { + } + }) + }.koin + + val a = Simple.Component2() + + val session1 = koin.createScope("session1", named("Session")) + + session1.declare(a, Simple.ComponentInterface1::class, named("another_a")) + assertEquals(a, session1.get(named("another_a"))) + } + + @Test + fun `can't declare a scoped on the fly with unsatisfactory primary type`() { + + val koin = koinApplication { + printLogger() + modules(module { + scope(named("Session")) { + } + }) + }.koin + + val a = Simple.Component2() + + val session1 = koin.createScope("session1", named("Session")) + + try { + session1.declare(a, Simple.ComponentInterface2::class) + fail() + } catch (e: BadDefinitionException) { + e.printStackTrace() + } + } + @Test fun `can't declare a scoped-single on the fly`() { diff --git a/koin-projects/koin-test/src/main/kotlin/org/koin/test/mock/Declare.kt b/koin-projects/koin-test/src/main/kotlin/org/koin/test/mock/Declare.kt index f07127bd4..2c7141440 100644 --- a/koin-projects/koin-test/src/main/kotlin/org/koin/test/mock/Declare.kt +++ b/koin-projects/koin-test/src/main/kotlin/org/koin/test/mock/Declare.kt @@ -22,6 +22,6 @@ inline fun KoinTest.declare( noinline instance: () -> T ): T { val koin = KoinContextHandler.get() - koin.declare(instance(), qualifier, override = true) + koin.declare(instance(), qualifier = qualifier, override = true) return get(qualifier) } \ No newline at end of file diff --git a/koin-projects/koin-test/src/main/kotlin/org/koin/test/mock/DeclareMock.kt b/koin-projects/koin-test/src/main/kotlin/org/koin/test/mock/DeclareMock.kt index 9cc3d3110..31eaec0b5 100644 --- a/koin-projects/koin-test/src/main/kotlin/org/koin/test/mock/DeclareMock.kt +++ b/koin-projects/koin-test/src/main/kotlin/org/koin/test/mock/DeclareMock.kt @@ -58,7 +58,7 @@ inline fun Scope.declareMock( stubbing: StubFunction = {} ): T { val mock = MockProvider.makeMock() - declare(mock, qualifier, secondaryTypes + T::class, true) + declare(mock, qualifier = qualifier, secondaryTypes = secondaryTypes + T::class, override = true) mock.apply(stubbing) return mock } From a385fd9e225bc35d242a411bd6412ad4407fce66 Mon Sep 17 00:00:00 2001 From: "shen.xudong" Date: Sat, 16 May 2020 16:40:35 +0800 Subject: [PATCH 2/2] use inline reified to support declare a component definition with primary type --- .../src/main/kotlin/org/koin/core/Koin.kt | 3 +- .../org/koin/core/definition/Definitions.kt | 2 +- .../koin/core/error/BadDefinitionException.kt | 3 -- .../main/kotlin/org/koin/core/scope/Scope.kt | 6 ++-- .../org/koin/core/scope/ScopeDefinition.kt | 8 ++--- .../java/org/koin/core/DeclareInstanceTest.kt | 30 ++----------------- .../main/kotlin/org/koin/test/mock/Declare.kt | 2 +- .../kotlin/org/koin/test/mock/DeclareMock.kt | 2 +- 8 files changed, 11 insertions(+), 45 deletions(-) delete mode 100644 koin-projects/koin-core/src/main/kotlin/org/koin/core/error/BadDefinitionException.kt diff --git a/koin-projects/koin-core/src/main/kotlin/org/koin/core/Koin.kt b/koin-projects/koin-core/src/main/kotlin/org/koin/core/Koin.kt index 2545799fa..2005ed032 100644 --- a/koin-projects/koin-core/src/main/kotlin/org/koin/core/Koin.kt +++ b/koin-projects/koin-core/src/main/kotlin/org/koin/core/Koin.kt @@ -139,13 +139,12 @@ class Koin { */ inline fun declare( instance: T, - clazz: KClass<*> = instance::class, qualifier: Qualifier? = null, secondaryTypes: List> = emptyList(), override: Boolean = false ) { val firstType = listOf(T::class) - _scopeRegistry.rootScope.declare(instance, clazz, qualifier, firstType + secondaryTypes, override) + _scopeRegistry.rootScope.declare(instance, qualifier, firstType + secondaryTypes, override) } /** diff --git a/koin-projects/koin-core/src/main/kotlin/org/koin/core/definition/Definitions.kt b/koin-projects/koin-core/src/main/kotlin/org/koin/core/definition/Definitions.kt index 1184a1473..b3a4a3300 100644 --- a/koin-projects/koin-core/src/main/kotlin/org/koin/core/definition/Definitions.kt +++ b/koin-projects/koin-core/src/main/kotlin/org/koin/core/definition/Definitions.kt @@ -35,7 +35,7 @@ object Definitions { ) } - internal fun createSingle( + fun createSingle( clazz: KClass<*>, qualifier: Qualifier? = null, definition: Definition<*>, diff --git a/koin-projects/koin-core/src/main/kotlin/org/koin/core/error/BadDefinitionException.kt b/koin-projects/koin-core/src/main/kotlin/org/koin/core/error/BadDefinitionException.kt deleted file mode 100644 index 6fcb115d2..000000000 --- a/koin-projects/koin-core/src/main/kotlin/org/koin/core/error/BadDefinitionException.kt +++ /dev/null @@ -1,3 +0,0 @@ -package org.koin.core.error - -class BadDefinitionException(str: String) : Exception(str) \ No newline at end of file diff --git a/koin-projects/koin-core/src/main/kotlin/org/koin/core/scope/Scope.kt b/koin-projects/koin-core/src/main/kotlin/org/koin/core/scope/Scope.kt index 6a004b7c7..ee5c4e1c1 100644 --- a/koin-projects/koin-core/src/main/kotlin/org/koin/core/scope/Scope.kt +++ b/koin-projects/koin-core/src/main/kotlin/org/koin/core/scope/Scope.kt @@ -260,19 +260,17 @@ data class Scope( * (single definition of th current scope is root) * * @param instance The instance you're declaring. - * @param clazz The primary type for this declaration * @param qualifier Qualifier for this declaration * @param secondaryTypes List of secondary bound types * @param override Allows to override a previous declaration of the same type (default to false). */ - fun declare( + inline fun declare( instance: T, - clazz: KClass<*> = instance::class, qualifier: Qualifier? = null, secondaryTypes: List>? = null, override: Boolean = false ) = synchronized(this) { - val definition = _scopeDefinition.saveNewDefinition(instance, clazz, qualifier, secondaryTypes, override) + val definition = _scopeDefinition.saveNewDefinition(instance, qualifier, secondaryTypes, override) _instanceRegistry.saveDefinition(definition, override = true) } diff --git a/koin-projects/koin-core/src/main/kotlin/org/koin/core/scope/ScopeDefinition.kt b/koin-projects/koin-core/src/main/kotlin/org/koin/core/scope/ScopeDefinition.kt index 3460e2c51..d31721e31 100644 --- a/koin-projects/koin-core/src/main/kotlin/org/koin/core/scope/ScopeDefinition.kt +++ b/koin-projects/koin-core/src/main/kotlin/org/koin/core/scope/ScopeDefinition.kt @@ -3,7 +3,6 @@ package org.koin.core.scope import org.koin.core.definition.BeanDefinition import org.koin.core.definition.Definitions import org.koin.core.definition.Options -import org.koin.core.error.BadDefinitionException import org.koin.core.error.DefinitionOverrideException import org.koin.core.qualifier.Qualifier import org.koin.core.qualifier._q @@ -35,16 +34,13 @@ class ScopeDefinition(val qualifier: Qualifier, val isRoot: Boolean = false, pri internal fun size() = definitions.size - fun saveNewDefinition( + inline fun saveNewDefinition( instance: T, - clazz: KClass<*> = instance::class, qualifier: Qualifier? = null, secondaryTypes: List>? = null, override: Boolean = false ): BeanDefinition { - if (!clazz.isInstance(instance)) { - throw BadDefinitionException("Primary type '$clazz' should be or supertype of '${instance::class}'") - } + val clazz = T::class val found: BeanDefinition<*>? = definitions.firstOrNull { def -> def.`is`(clazz, qualifier, this) } if (found != null) { diff --git a/koin-projects/koin-core/src/test/java/org/koin/core/DeclareInstanceTest.kt b/koin-projects/koin-core/src/test/java/org/koin/core/DeclareInstanceTest.kt index 40595f9b4..d5a743795 100644 --- a/koin-projects/koin-core/src/test/java/org/koin/core/DeclareInstanceTest.kt +++ b/koin-projects/koin-core/src/test/java/org/koin/core/DeclareInstanceTest.kt @@ -4,7 +4,6 @@ import org.junit.Assert.* import org.junit.Ignore import org.junit.Test import org.koin.Simple -import org.koin.core.error.BadDefinitionException import org.koin.core.error.DefinitionOverrideException import org.koin.core.error.NoBeanDefFoundException import org.koin.core.logger.Level @@ -97,7 +96,7 @@ class DeclareInstanceTest { val a = Simple.ComponentA() - koin.declare(a, qualifier = named("another_a")) + koin.declare(a, named("another_a")) assertEquals(a, koin.get(named("another_a"))) assertNotEquals(a, koin.get()) @@ -116,7 +115,7 @@ class DeclareInstanceTest { val a = Simple.ComponentA() - koin.declare(a, qualifier = named("another_a"), override = true) + koin.declare(a, named("another_a"), override = true) assertEquals(a, koin.get(named("another_a"))) assertNotEquals(a, koin.get()) @@ -209,33 +208,10 @@ class DeclareInstanceTest { val session1 = koin.createScope("session1", named("Session")) - session1.declare(a, Simple.ComponentInterface1::class, named("another_a")) + session1.declare(a, named("another_a")) assertEquals(a, session1.get(named("another_a"))) } - @Test - fun `can't declare a scoped on the fly with unsatisfactory primary type`() { - - val koin = koinApplication { - printLogger() - modules(module { - scope(named("Session")) { - } - }) - }.koin - - val a = Simple.Component2() - - val session1 = koin.createScope("session1", named("Session")) - - try { - session1.declare(a, Simple.ComponentInterface2::class) - fail() - } catch (e: BadDefinitionException) { - e.printStackTrace() - } - } - @Test fun `can't declare a scoped-single on the fly`() { diff --git a/koin-projects/koin-test/src/main/kotlin/org/koin/test/mock/Declare.kt b/koin-projects/koin-test/src/main/kotlin/org/koin/test/mock/Declare.kt index 2c7141440..f07127bd4 100644 --- a/koin-projects/koin-test/src/main/kotlin/org/koin/test/mock/Declare.kt +++ b/koin-projects/koin-test/src/main/kotlin/org/koin/test/mock/Declare.kt @@ -22,6 +22,6 @@ inline fun KoinTest.declare( noinline instance: () -> T ): T { val koin = KoinContextHandler.get() - koin.declare(instance(), qualifier = qualifier, override = true) + koin.declare(instance(), qualifier, override = true) return get(qualifier) } \ No newline at end of file diff --git a/koin-projects/koin-test/src/main/kotlin/org/koin/test/mock/DeclareMock.kt b/koin-projects/koin-test/src/main/kotlin/org/koin/test/mock/DeclareMock.kt index 31eaec0b5..9cc3d3110 100644 --- a/koin-projects/koin-test/src/main/kotlin/org/koin/test/mock/DeclareMock.kt +++ b/koin-projects/koin-test/src/main/kotlin/org/koin/test/mock/DeclareMock.kt @@ -58,7 +58,7 @@ inline fun Scope.declareMock( stubbing: StubFunction = {} ): T { val mock = MockProvider.makeMock() - declare(mock, qualifier = qualifier, secondaryTypes = secondaryTypes + T::class, override = true) + declare(mock, qualifier, secondaryTypes + T::class, true) mock.apply(stubbing) return mock }