Skip to content

Commit 15bef1d

Browse files
committed
Add docs and unit tests for the new() parameterized function
1 parent 86d5b28 commit 15bef1d

File tree

3 files changed

+173
-1
lines changed

3 files changed

+173
-1
lines changed

doc/modules/core/pages/bindings.adoc

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -392,6 +392,26 @@ val di = DI {
392392
<1> Binding of `Dice`. It gets its transitive dependencies.
393393
394394
Those tricks are limited to 0 to 10 constructor parameters.
395+
396+
==== Mixing manual and auto-resolved constructor arguments
397+
398+
You can also specify some constructor arguments manually while letting Kodein-DI auto-resolve the others:
399+
400+
[source, kotlin]
401+
.Example: mixing manual and auto-resolved arguments
402+
----
403+
class GameEngine(val dice: Dice, val maxPlayers: Int, val gameName: String)
404+
405+
val di = DI {
406+
bindSingleton<Dice> { RandomDice(6) }
407+
bindSingleton<GameEngine> {
408+
new(::GameEngine, a2 = 4, a3 = "Rolling Dice") // <1>
409+
}
410+
}
411+
----
412+
<1> The `dice` parameter is auto-resolved from the container, while `maxPlayers` and `gameName` are provided manually.
413+
414+
You can specify any combination of arguments using their position (`a1`, `a2`, `a3`, etc.), and all non-specified arguments will be automatically retrieved from the DI container.
395415
====
396416

397417
The binding functions are in the same environment as the `newInstance` function described in the <<injection, dependency injection section>>.

doc/modules/core/pages/injection-retrieval.adoc

Lines changed: 40 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -116,7 +116,46 @@ val di = DI {
116116

117117
This function is available for classes with up to 22 constructor parameters.
118118

119-
This function also supports using arguments, such as those in `bindFactory` or `bindMultiton` functions.
119+
==== Mixing manual and auto-resolved arguments
120+
121+
You can also provide specific constructor arguments manually while letting the rest be auto-resolved from the DI container.
122+
This is useful when you need to pass configuration values or runtime parameters:
123+
124+
[source,kotlin]
125+
----
126+
class GameEngine(val dice: Dice, val maxPlayers: Int, val gameName: String)
127+
128+
val di = DI {
129+
bind<Dice> { singleton { RandomDice(6) } }
130+
bind<GameEngine> {
131+
singleton {
132+
new(::GameEngine, a2 = 4, a3 = "Poker") // <1>
133+
}
134+
}
135+
}
136+
----
137+
<1> The `dice` parameter (position 1) is auto-resolved, while `maxPlayers` (position 2) and `gameName` (position 3) are provided manually.
138+
139+
You can specify any combination of arguments using their position (`a1`, `a2`, `a3`, etc.):
140+
141+
[source,kotlin]
142+
----
143+
class Config(val host: String, val port: Int, val db: Database, val timeout: Int)
144+
145+
val di = DI {
146+
bindSingleton<Database> { PostgresDB() }
147+
bindSingleton<Config> {
148+
new(::Config, a1 = "localhost", a2 = 8080, a4 = 30) // <1>
149+
}
150+
}
151+
----
152+
<1> Parameters 1, 2, and 4 are provided manually, while parameter 3 (`db`) is auto-resolved from the container.
153+
154+
NOTE: All non-specified arguments will be automatically retrieved from the DI container using `instance()`.
155+
156+
==== Using factory/multiton arguments with `new`
157+
158+
This function also supports using arguments from `bindFactory` or `bindMultiton` functions.
120159
For them, provide your argument type in the lambda parameter (that way you don't need to specify type arguments),
121160
and then pass it as the first parameter to the `new` function:
122161

kodein-di/src/commonTest/kotlin/org/kodein/di/Tests_26_New.kt

Lines changed: 113 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,4 +75,117 @@ internal class Tests_26_New {
7575

7676
assertNotSame(a, b.a)
7777
}
78+
79+
class C(val a: A, val x: Int, val y: String)
80+
81+
@Test
82+
fun test_04_new_with_named_args_all_manual() {
83+
val di = DI {
84+
bindSingleton { new(::A) }
85+
bindSingleton { new(::C, a1 = A(), a2 = 42, a3 = "test") }
86+
}
87+
88+
val c: C by di.instance()
89+
val a: A by di.instance()
90+
91+
assertNotSame(a, c.a)
92+
kotlin.test.assertEquals(42, c.x)
93+
kotlin.test.assertEquals("test", c.y)
94+
}
95+
96+
@Test
97+
fun test_05_new_with_named_args_partial() {
98+
val di = DI {
99+
bindSingleton { new(::A) }
100+
bindSingleton { new(::C, a2 = 99, a3 = "partial") }
101+
}
102+
103+
val c: C by di.instance()
104+
val a: A by di.instance()
105+
106+
assertSame(a, c.a)
107+
kotlin.test.assertEquals(99, c.x)
108+
kotlin.test.assertEquals("partial", c.y)
109+
}
110+
111+
@Test
112+
fun test_06_new_with_named_args_skip_middle() {
113+
val di = DI {
114+
bindSingleton { new(::A) }
115+
bindSingleton { new(::C, a1 = A(), a3 = "skip") }
116+
}
117+
118+
119+
kotlin.test.assertFailsWith<DI.NotFoundException> {
120+
val c: C by di.instance()
121+
c.x
122+
}
123+
}
124+
125+
class D(val x: Int, val y: Int, val z: Int, val w: Int)
126+
127+
@Test
128+
fun test_07_new_with_multiple_named_args() {
129+
val di = DI {
130+
bindSingleton { new(::D, a1 = 1, a2 = 2, a3 = 3, a4 = 4) }
131+
}
132+
133+
val d: D by di.instance()
134+
kotlin.test.assertEquals(1, d.x)
135+
kotlin.test.assertEquals(2, d.y)
136+
kotlin.test.assertEquals(3, d.z)
137+
kotlin.test.assertEquals(4, d.w)
138+
}
139+
140+
@Test
141+
fun test_08_new_with_named_args_and_bindings() {
142+
val di = DI {
143+
bindConstant("x") { 100 }
144+
bindConstant("y") { 200 }
145+
bindConstant("z") { 300 }
146+
bindConstant("w") { 400 }
147+
bindSingleton { new(::D, a2 = 222, a4 = 444) }
148+
}
149+
150+
151+
kotlin.test.assertFailsWith<DI.NotFoundException> {
152+
val d: D by di.instance()
153+
d.x
154+
}
155+
}
156+
157+
class E(val a: A, val b: B)
158+
159+
@Test
160+
fun test_09_new_with_mixed_dependencies() {
161+
val di = DI {
162+
bind { singleton { new(::A) } }
163+
bind { singleton { new(::B) } }
164+
bind { singleton { new(::E, a2 = B(A())) } }
165+
}
166+
167+
val e: E by di.instance()
168+
val a: A by di.instance()
169+
val b: B by di.instance()
170+
171+
assertSame(a, e.a)
172+
assertNotSame(b, e.b)
173+
}
174+
175+
@Test
176+
fun test_10_new_with_provider_and_named_args() {
177+
val di = DI {
178+
bindSingleton { new(::A) }
179+
bindProvider { new(::C, a2 = 10, a3 = "provider") }
180+
}
181+
182+
val c1: C by di.instance()
183+
val c2: C by di.instance()
184+
185+
assertNotSame(c1, c2)
186+
kotlin.test.assertEquals(10, c1.x)
187+
kotlin.test.assertEquals(10, c2.x)
188+
kotlin.test.assertEquals("provider", c1.y)
189+
kotlin.test.assertEquals("provider", c2.y)
190+
}
78191
}

0 commit comments

Comments
 (0)