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