From ef1b033b7846bd9071f1ede9a0c57996f24d32c5 Mon Sep 17 00:00:00 2001 From: Denis Date: Tue, 27 Feb 2018 04:51:55 +0300 Subject: [PATCH] BAEL-1462 Kotlin DI with Kodein (#3544) * BAEL-1462 Kotlin DI with Kodein * BAEL-1462 Kotlin DI with Kodein * applied editor's suggestions * removed unnecessary curly braces * Moved kodein files into core-kotlin as per editor's review * Using assertj instead of junit assertions as per editor's instruction --- core-kotlin/pom.xml | 15 +- .../com/baeldung/kotlin/kodein/Controller.kt | 3 + .../kotlin/com/baeldung/kotlin/kodein/Dao.kt | 3 + .../com/baeldung/kotlin/kodein/JdbcDao.kt | 3 + .../com/baeldung/kotlin/kodein/MongoDao.kt | 3 + .../com/baeldung/kotlin/kodein/Service.kt | 3 + .../baeldung/kotlin/kodein/KodeinUnitTest.kt | 191 ++++++++++++++++++ 7 files changed, 220 insertions(+), 1 deletion(-) create mode 100644 core-kotlin/src/main/kotlin/com/baeldung/kotlin/kodein/Controller.kt create mode 100644 core-kotlin/src/main/kotlin/com/baeldung/kotlin/kodein/Dao.kt create mode 100644 core-kotlin/src/main/kotlin/com/baeldung/kotlin/kodein/JdbcDao.kt create mode 100644 core-kotlin/src/main/kotlin/com/baeldung/kotlin/kodein/MongoDao.kt create mode 100644 core-kotlin/src/main/kotlin/com/baeldung/kotlin/kodein/Service.kt create mode 100644 core-kotlin/src/test/kotlin/com/baeldung/kotlin/kodein/KodeinUnitTest.kt diff --git a/core-kotlin/pom.xml b/core-kotlin/pom.xml index 33bdbf719f..36298ca084 100644 --- a/core-kotlin/pom.xml +++ b/core-kotlin/pom.xml @@ -76,7 +76,18 @@ mockito-kotlin ${mockito-kotlin.version} test - + + + com.github.salomonbrys.kodein + kodein + ${kodein.version} + + + org.assertj + assertj-core + ${assertj.version} + test + @@ -189,11 +200,13 @@ 1.1.2 0.15 1.5.0 + 4.1.0 5.0.0 1.0.0 4.12.0 4.12 + 3.9.1 diff --git a/core-kotlin/src/main/kotlin/com/baeldung/kotlin/kodein/Controller.kt b/core-kotlin/src/main/kotlin/com/baeldung/kotlin/kodein/Controller.kt new file mode 100644 index 0000000000..721bdb04bc --- /dev/null +++ b/core-kotlin/src/main/kotlin/com/baeldung/kotlin/kodein/Controller.kt @@ -0,0 +1,3 @@ +package com.baeldung.kotlin.kodein + +class Controller(private val service : Service) \ No newline at end of file diff --git a/core-kotlin/src/main/kotlin/com/baeldung/kotlin/kodein/Dao.kt b/core-kotlin/src/main/kotlin/com/baeldung/kotlin/kodein/Dao.kt new file mode 100644 index 0000000000..a0be7ef0e0 --- /dev/null +++ b/core-kotlin/src/main/kotlin/com/baeldung/kotlin/kodein/Dao.kt @@ -0,0 +1,3 @@ +package com.baeldung.kotlin.kodein + +interface Dao \ No newline at end of file diff --git a/core-kotlin/src/main/kotlin/com/baeldung/kotlin/kodein/JdbcDao.kt b/core-kotlin/src/main/kotlin/com/baeldung/kotlin/kodein/JdbcDao.kt new file mode 100644 index 0000000000..0a09b95dbf --- /dev/null +++ b/core-kotlin/src/main/kotlin/com/baeldung/kotlin/kodein/JdbcDao.kt @@ -0,0 +1,3 @@ +package com.baeldung.kotlin.kodein + +class JdbcDao : Dao \ No newline at end of file diff --git a/core-kotlin/src/main/kotlin/com/baeldung/kotlin/kodein/MongoDao.kt b/core-kotlin/src/main/kotlin/com/baeldung/kotlin/kodein/MongoDao.kt new file mode 100644 index 0000000000..06436fcd21 --- /dev/null +++ b/core-kotlin/src/main/kotlin/com/baeldung/kotlin/kodein/MongoDao.kt @@ -0,0 +1,3 @@ +package com.baeldung.kotlin.kodein + +class MongoDao : Dao \ No newline at end of file diff --git a/core-kotlin/src/main/kotlin/com/baeldung/kotlin/kodein/Service.kt b/core-kotlin/src/main/kotlin/com/baeldung/kotlin/kodein/Service.kt new file mode 100644 index 0000000000..bb24a5cc21 --- /dev/null +++ b/core-kotlin/src/main/kotlin/com/baeldung/kotlin/kodein/Service.kt @@ -0,0 +1,3 @@ +package com.baeldung.kotlin.kodein + +class Service(private val dao: Dao, private val tag: String) \ No newline at end of file diff --git a/core-kotlin/src/test/kotlin/com/baeldung/kotlin/kodein/KodeinUnitTest.kt b/core-kotlin/src/test/kotlin/com/baeldung/kotlin/kodein/KodeinUnitTest.kt new file mode 100644 index 0000000000..7776eebd52 --- /dev/null +++ b/core-kotlin/src/test/kotlin/com/baeldung/kotlin/kodein/KodeinUnitTest.kt @@ -0,0 +1,191 @@ +package com.baeldung.kotlin.kodein + +import com.github.salomonbrys.kodein.* +import org.assertj.core.api.Assertions.assertThat +import org.junit.Test + +class KodeinUnitTest { + + class InMemoryDao : Dao + + @Test + fun whenSingletonBinding_thenSingleInstanceIsCreated() { + var created = false + val kodein = Kodein { + bind() with singleton { + created = true + MongoDao() + } + } + + assertThat(created).isFalse() + + val dao1: Dao = kodein.instance() + + assertThat(created).isTrue() + + val dao2: Dao = kodein.instance() + + assertThat(dao1).isSameAs(dao2) + } + + @Test + fun whenFactoryBinding_thenNewInstanceIsCreated() { + val kodein = Kodein { + bind() with singleton { MongoDao() } + bind() with factory { tag: String -> Service(instance(), tag) } + } + val service1: Service = kodein.with("myTag").instance() + val service2: Service = kodein.with("myTag").instance() + + assertThat(service1).isNotSameAs(service2) + } + + @Test + fun whenProviderBinding_thenNewInstanceIsCreated() { + val kodein = Kodein { + bind() with provider { MongoDao() } + } + val dao1: Dao = kodein.instance() + val dao2: Dao = kodein.instance() + + assertThat(dao1).isNotSameAs(dao2) + } + + @Test + fun whenTaggedBinding_thenMultipleInstancesOfSameTypeCanBeRegistered() { + val kodein = Kodein { + bind("dao1") with singleton { MongoDao() } + bind("dao2") with singleton { MongoDao() } + } + val dao1: Dao = kodein.instance("dao1") + val dao2: Dao = kodein.instance("dao2") + + assertThat(dao1).isNotSameAs(dao2) + } + + @Test + fun whenEagerSingletonBinding_thenCreationIsEager() { + var created = false + val kodein = Kodein { + bind() with eagerSingleton { + created = true + MongoDao() + } + } + + assertThat(created).isTrue() + val dao1: Dao = kodein.instance() + val dao2: Dao = kodein.instance() + + assertThat(dao1).isSameAs(dao2) + } + + @Test + fun whenMultitonBinding_thenInstancesAreReused() { + val kodein = Kodein { + bind() with singleton { MongoDao() } + bind() with multiton { tag: String -> Service(instance(), tag) } + } + val service1: Service = kodein.with("myTag").instance() + val service2: Service = kodein.with("myTag").instance() + + assertThat(service1).isSameAs(service2) + } + + @Test + fun whenInstanceBinding_thenItIsReused() { + val dao = MongoDao() + val kodein = Kodein { + bind() with instance(dao) + } + val fromContainer: Dao = kodein.instance() + + assertThat(dao).isSameAs(fromContainer) + } + + @Test + fun whenConstantBinding_thenItIsAvailable() { + val kodein = Kodein { + constant("magic") with 42 + } + val fromContainer: Int = kodein.instance("magic") + + assertThat(fromContainer).isEqualTo(42) + } + + @Test + fun whenUsingModules_thenTransitiveDependenciesAreSuccessfullyResolved() { + val jdbcModule = Kodein.Module { + bind() with singleton { JdbcDao() } + } + val kodein = Kodein { + import(jdbcModule) + bind() with singleton { Controller(instance()) } + bind() with singleton { Service(instance(), "myService") } + } + + val dao: Dao = kodein.instance() + assertThat(dao).isInstanceOf(JdbcDao::class.java) + } + + @Test + fun whenComposition_thenBeansAreReUsed() { + val persistenceContainer = Kodein { + bind() with singleton { MongoDao() } + } + val serviceContainer = Kodein { + extend(persistenceContainer) + bind() with singleton { Service(instance(), "myService") } + } + val fromPersistence: Dao = persistenceContainer.instance() + val fromService: Dao = serviceContainer.instance() + + assertThat(fromPersistence).isSameAs(fromService) + } + + @Test + fun whenOverriding_thenRightBeanIsUsed() { + val commonModule = Kodein.Module { + bind() with singleton { MongoDao() } + bind() with singleton { Service(instance(), "myService") } + } + val testContainer = Kodein { + import(commonModule) + bind(overrides = true) with singleton { InMemoryDao() } + } + val dao: Dao = testContainer.instance() + + assertThat(dao).isInstanceOf(InMemoryDao::class.java) + } + + @Test + fun whenMultiBinding_thenWorks() { + val kodein = Kodein { + bind() from setBinding() + bind().inSet() with singleton { MongoDao() } + bind().inSet() with singleton { JdbcDao() } + } + val daos: Set = kodein.instance() + + assertThat(daos.map { it.javaClass as Class<*> }).containsOnly(MongoDao::class.java, JdbcDao::class.java) + } + + @Test + fun whenInjector_thenWorks() { + class Controller2 { + private val injector = KodeinInjector() + val service: Service by injector.instance() + fun injectDependencies(kodein: Kodein) = injector.inject(kodein) + } + + val kodein = Kodein { + bind() with singleton { MongoDao() } + bind() with singleton { Service(instance(), "myService") } + } + val controller = Controller2() + controller.injectDependencies(kodein) + + assertThat(controller.service).isNotNull + } +} \ No newline at end of file