0
# Binding DSL
1
2
Declarative syntax for binding types to their implementations with various creation patterns including singleton, provider, factory, instance, and multiton bindings.
3
4
## Capabilities
5
6
### Core Binding Methods
7
8
Generic binding methods that form the foundation of the DSL syntax for attaching types to their creation strategies.
9
10
```kotlin { .api }
11
/**
12
* Core binding interface for type-to-implementation mappings
13
*/
14
interface DI.Builder {
15
/**
16
* Start binding a specific type with optional tag and override settings
17
* @param type TypeToken representing the type to bind
18
* @param tag Optional tag for disambiguation
19
* @param overrides Whether this binding may override existing bindings
20
* @return TypeBinder for completing the binding with 'with' clause
21
*/
22
fun <T : Any> Bind(type: TypeToken<out T>, tag: Any? = null, overrides: Boolean? = null): TypeBinder<T>
23
24
/**
25
* Directly attach a pre-created binding to the container
26
* @param tag Optional tag for the binding
27
* @param overrides Whether this binding may override existing bindings
28
* @param binding The binding implementation to attach
29
*/
30
fun <T : Any> Bind(tag: Any? = null, overrides: Boolean? = null, binding: DIBinding<*, *, T>)
31
32
/**
33
* Create a constant binding with a specific tag
34
* @param tag Required tag for the constant
35
* @param overrides Whether this binding may override existing bindings
36
* @return ConstantBinder for completing the binding
37
*/
38
fun constant(tag: Any, overrides: Boolean? = null): ConstantBinder
39
40
/**
41
* Create a delegate binding that forwards to another binding
42
* @param type TypeToken for the type being delegated
43
* @param tag Optional tag for the delegation
44
* @param overrides Whether this binding may override existing bindings
45
* @return DelegateBinder for specifying the target binding
46
*/
47
fun <T : Any> Delegate(
48
type: TypeToken<out T>,
49
tag: Any? = null,
50
overrides: Boolean? = null
51
): DelegateBinder<T>
52
}
53
54
/**
55
* Type binder for completing binding syntax with 'with' keyword
56
*/
57
interface DI.Builder.TypeBinder<T : Any> {
58
/**
59
* Complete the binding by attaching a specific binding implementation
60
* @param binding The binding that creates instances of type T
61
*/
62
infix fun <C : Any, A> with(binding: DIBinding<in C, in A, out T>)
63
}
64
65
/**
66
* Constant binder for binding tagged constants
67
*/
68
interface DI.Builder.ConstantBinder {
69
/**
70
* Bind a constant value with specific type
71
* @param valueType TypeToken for the constant's type
72
* @param value The constant value to bind
73
*/
74
fun <T : Any> With(valueType: TypeToken<out T>, value: T)
75
}
76
77
/**
78
* Set binder for managing multiple bindings of the same type in a Set
79
*/
80
interface DI.Builder.SetBinder<T : Any> {
81
/**
82
* Add a binding to the set without adding it to the main container
83
* @param createBinding Function that creates the binding to add
84
*/
85
fun add(createBinding: () -> DIBinding<*, *, out T>)
86
87
/**
88
* Add a binding to both the set and the main container
89
* @param tag Optional tag for the individual binding
90
* @param overrides Whether this binding may override existing bindings
91
* @param createBinding Function that creates the binding to add
92
*/
93
fun bind(tag: Any? = null, overrides: Boolean? = null, createBinding: () -> DIBinding<*, *, out T>)
94
}
95
96
/**
97
* Argument set binder for managing multiple factory bindings of the same type in a Set
98
*/
99
interface DI.Builder.ArgSetBinder<A : Any, T : Any> {
100
/**
101
* Add a factory binding to the set without adding it to the main container
102
* @param createBinding Function that creates the factory binding to add
103
*/
104
fun add(createBinding: () -> DIBinding<*, in A, out T>)
105
106
/**
107
* Add a factory binding to both the set and the main container
108
* @param tag Optional tag for the individual binding
109
* @param overrides Whether this binding may override existing bindings
110
* @param createBinding Function that creates the factory binding to add
111
*/
112
fun bind(
113
tag: Any? = null,
114
overrides: Boolean? = null,
115
createBinding: () -> DIBinding<*, in A, out T>,
116
)
117
}
118
```
119
120
### Set Binding Methods
121
122
Methods for creating and managing set bindings that collect multiple implementations of the same interface.
123
124
```kotlin { .api }
125
/**
126
* Create a new set binding and configure it with multiple bindings
127
* @param tag Optional tag for the set binding
128
* @param overrides Whether this set binding may override existing bindings
129
* @param type TypeToken for the set element type
130
* @param creator Configuration function for adding bindings to the set
131
*/
132
fun <T : Any> DI.Builder.BindInSet(
133
tag: Any? = null,
134
overrides: Boolean? = null,
135
type: TypeToken<out T>,
136
creator: SetBinder<T>.() -> Unit,
137
)
138
139
/**
140
* Add bindings to an existing set binding
141
* @param tag Optional tag for the set binding to add to
142
* @param overrides Whether added bindings may override existing bindings
143
* @param type TypeToken for the set element type
144
* @param creator Configuration function for adding bindings to the set
145
*/
146
fun <T : Any> DI.Builder.InBindSet(
147
tag: Any? = null,
148
overrides: Boolean? = null,
149
type: TypeToken<out T>,
150
creator: SetBinder<T>.() -> Unit,
151
)
152
153
/**
154
* Create a new argument set binding for factory collections
155
* @param tag Optional tag for the set binding
156
* @param overrides Whether this set binding may override existing bindings
157
* @param argType TypeToken for the factory argument type
158
* @param type TypeToken for the factory return type
159
* @param creator Configuration function for adding factory bindings to the set
160
*/
161
fun <A : Any, T : Any> DI.Builder.BindInArgSet(
162
tag: Any? = null,
163
overrides: Boolean? = null,
164
argType: TypeToken<in A>,
165
type: TypeToken<out T>,
166
creator: ArgSetBinder<A, T>.() -> Unit,
167
)
168
169
/**
170
* Add factory bindings to an existing argument set binding
171
* @param tag Optional tag for the set binding to add to
172
* @param overrides Whether added bindings may override existing bindings
173
* @param argType TypeToken for the factory argument type
174
* @param type TypeToken for the factory return type
175
* @param creator Configuration function for adding factory bindings to the set
176
*/
177
fun <A : Any, T : Any> DI.Builder.InBindArgSet(
178
tag: Any? = null,
179
overrides: Boolean? = null,
180
argType: TypeToken<in A>,
181
type: TypeToken<out T>,
182
creator: ArgSetBinder<A, T>.() -> Unit,
183
)
184
185
/**
186
* Add a single binding to an existing set binding
187
* @param tag Optional tag for the set binding to add to
188
* @param overrides Whether this binding may override existing bindings
189
* @param binding The binding to add to the set
190
*/
191
fun <T : Any> DI.Builder.AddBindInSet(
192
tag: Any? = null,
193
overrides: Boolean? = null,
194
binding: DIBinding<*, *, T>,
195
)
196
```
197
198
### Constructor Injection Binding Methods
199
200
Convenience methods for binding types using their constructors with automatic dependency injection. These methods support up to 22 constructor parameters and automatically resolve dependencies for each parameter.
201
202
```kotlin { .api }
203
/**
204
* Bind a singleton using constructor injection (0-22 parameters)
205
* @param constructor Constructor function reference (e.g., ::MyClass)
206
* @param tag Optional tag for the binding
207
* @param overrides Whether this binding may override existing bindings
208
* @param sync Whether the singleton creation should be synchronized
209
*/
210
fun <T : Any> DI.Builder.bindSingletonOf(
211
crossinline constructor: () -> T,
212
tag: Any? = null,
213
overrides: Boolean? = null,
214
sync: Boolean = true,
215
): Unit
216
217
fun <T : Any, P1> DI.Builder.bindSingletonOf(
218
crossinline constructor: (P1) -> T,
219
tag: Any? = null,
220
overrides: Boolean? = null,
221
sync: Boolean = true,
222
): Unit
223
224
fun <T : Any, P1, P2> DI.Builder.bindSingletonOf(
225
crossinline constructor: (P1, P2) -> T,
226
tag: Any? = null,
227
overrides: Boolean? = null,
228
sync: Boolean = true,
229
): Unit
230
231
fun <T : Any, P1, P2, P3> DI.Builder.bindSingletonOf(
232
crossinline constructor: (P1, P2, P3) -> T,
233
tag: Any? = null,
234
overrides: Boolean? = null,
235
sync: Boolean = true,
236
): Unit
237
// ... continues up to 22 parameters
238
239
/**
240
* Bind a provider using constructor injection (0-22 parameters)
241
* @param constructor Constructor function reference (e.g., ::MyClass)
242
* @param tag Optional tag for the binding
243
* @param overrides Whether this binding may override existing bindings
244
*/
245
fun <T : Any> DI.Builder.bindProviderOf(
246
crossinline constructor: () -> T,
247
tag: Any? = null,
248
overrides: Boolean? = null,
249
): Unit
250
251
fun <T : Any, P1> DI.Builder.bindProviderOf(
252
crossinline constructor: (P1) -> T,
253
tag: Any? = null,
254
overrides: Boolean? = null,
255
): Unit
256
257
fun <T : Any, P1, P2> DI.Builder.bindProviderOf(
258
crossinline constructor: (P1, P2) -> T,
259
tag: Any? = null,
260
overrides: Boolean? = null,
261
): Unit
262
263
fun <T : Any, P1, P2, P3> DI.Builder.bindProviderOf(
264
crossinline constructor: (P1, P2, P3) -> T,
265
tag: Any? = null,
266
overrides: Boolean? = null,
267
): Unit
268
// ... continues up to 22 parameters
269
270
/**
271
* Bind an eager singleton using constructor injection (0-22 parameters)
272
* @param constructor Constructor function reference (e.g., ::MyClass)
273
* @param tag Optional tag for the binding
274
* @param overrides Whether this binding may override existing bindings
275
*/
276
fun <T : Any> DI.Builder.bindEagerSingletonOf(
277
crossinline constructor: () -> T,
278
tag: Any? = null,
279
overrides: Boolean? = null,
280
): Unit
281
282
fun <T : Any, P1> DI.Builder.bindEagerSingletonOf(
283
crossinline constructor: (P1) -> T,
284
tag: Any? = null,
285
overrides: Boolean? = null,
286
): Unit
287
// ... continues up to 22 parameters
288
```
289
290
**Usage Examples:**
291
292
```kotlin
293
import org.kodein.di.*
294
295
class DatabaseConfig(val url: String, val maxConnections: Int)
296
class DatabaseService(private val config: DatabaseConfig)
297
class UserRepository(private val db: DatabaseService, private val logger: Logger)
298
class UserService(private val repository: UserRepository, private val validator: UserValidator)
299
300
val di = DI {
301
// Bind configuration
302
bindInstance<DatabaseConfig> { DatabaseConfig("jdbc:h2:mem:test", 10) }
303
bindInstance<Logger> { ConsoleLogger() }
304
305
// Use constructor injection - dependencies automatically resolved
306
bindSingletonOf(::DatabaseService) // Injects DatabaseConfig
307
bindSingletonOf(::UserRepository) // Injects DatabaseService and Logger
308
bindProviderOf(::UserValidator) // Creates new validator instances
309
bindSingletonOf(::UserService) // Injects UserRepository and UserValidator
310
}
311
```
312
313
### Factory Bindings
314
315
Factory bindings create new instances each time they are requested, accepting an argument to customize the created instance.
316
317
```kotlin { .api }
318
/**
319
* Factory binding that takes an argument and returns a new instance
320
* @param C Context type for scoped bindings
321
* @param A Argument type for the factory function
322
* @param T Return type of the created instances
323
*/
324
class Factory<C : Any, A, T : Any> : DIBinding<C, A, T>
325
326
/**
327
* Create a factory binding within a BindBuilder context
328
* @param creator Function that creates instances from arguments
329
* @return Factory binding instance
330
*/
331
fun <A, T : Any> DI.BindBuilder<*>.factory(
332
creator: BindingDI<*>.(A) -> T
333
): Factory<*, A, T>
334
335
/**
336
* Directly bind a factory with convenience method
337
* @param tag Optional tag for the binding
338
* @param overrides Whether this binding may override existing bindings
339
* @param creator Function that creates instances from arguments
340
*/
341
fun <A, T : Any> DI.Builder.bindFactory(
342
tag: Any? = null,
343
overrides: Boolean? = null,
344
creator: DirectDI.(A) -> T
345
)
346
```
347
348
### Provider Bindings
349
350
Provider bindings create new instances each time they are requested, taking no arguments (no-argument factories).
351
352
```kotlin { .api }
353
/**
354
* Provider binding that creates new instances without arguments
355
* @param C Context type for scoped bindings
356
* @param T Return type of the created instances
357
*/
358
class Provider<C : Any, T : Any> : DIBinding<C, Unit, T>
359
360
/**
361
* Create a provider binding within a BindBuilder context
362
* @param creator Function that creates instances
363
* @return Provider binding instance
364
*/
365
fun <T : Any> DI.BindBuilder<*>.provider(
366
creator: NoArgBindingDI<*>.() -> T
367
): Provider<*, T>
368
369
/**
370
* Directly bind a provider with convenience method
371
* @param tag Optional tag for the binding
372
* @param overrides Whether this binding may override existing bindings
373
* @param creator Function that creates instances
374
*/
375
fun <T : Any> DI.Builder.bindProvider(
376
tag: Any? = null,
377
overrides: Boolean? = null,
378
creator: DirectDI.() -> T
379
)
380
381
/**
382
* Bind a provider using constructor injection (up to 22 parameters)
383
* @param constructor Constructor function reference
384
* @param tag Optional tag for the binding
385
* @param overrides Whether this binding may override existing bindings
386
*/
387
fun <T : Any> DI.Builder.bindProviderOf(
388
constructor: () -> T,
389
tag: Any? = null,
390
overrides: Boolean? = null
391
)
392
393
fun <P1, T : Any> DI.Builder.bindProviderOf(
394
constructor: (P1) -> T,
395
tag: Any? = null,
396
overrides: Boolean? = null
397
)
398
399
// ... up to 22 parameter overloads
400
```
401
402
### Singleton Bindings
403
404
Singleton bindings create one instance per scope and reuse it for all subsequent requests within that scope.
405
406
```kotlin { .api }
407
/**
408
* Singleton binding that creates one instance per scope
409
* @param C Context type for the scoped singleton
410
* @param T Return type of the singleton instance
411
*/
412
class Singleton<C : Any, T : Any> : DIBinding<C, Unit, T>
413
414
/**
415
* Create a singleton binding within a scoped BindBuilder context
416
* @param ref Reference type for instance storage (default, thread-local, etc.)
417
* @param sync Whether to synchronize access to the singleton
418
* @param creator Function that creates the singleton instance
419
* @return Singleton binding instance
420
*/
421
fun <T : Any> DI.BindBuilder.WithScope<*>.singleton(
422
ref: RefMaker = SingletonReference,
423
sync: Boolean = true,
424
creator: NoArgBindingDI<*>.() -> T
425
): Singleton<*, T>
426
427
/**
428
* Directly bind a singleton with convenience method
429
* @param tag Optional tag for the binding
430
* @param overrides Whether this binding may override existing bindings
431
* @param sync Whether to synchronize access to the singleton
432
* @param creator Function that creates the singleton instance
433
*/
434
fun <T : Any> DI.Builder.bindSingleton(
435
tag: Any? = null,
436
overrides: Boolean? = null,
437
sync: Boolean = true,
438
creator: DirectDI.() -> T
439
)
440
441
/**
442
* Bind a singleton using constructor injection (up to 22 parameters)
443
* @param constructor Constructor function reference
444
* @param tag Optional tag for the binding
445
* @param overrides Whether this binding may override existing bindings
446
* @param sync Whether to synchronize access to the singleton
447
*/
448
fun <T : Any> DI.Builder.bindSingletonOf(
449
constructor: () -> T,
450
tag: Any? = null,
451
overrides: Boolean? = null,
452
sync: Boolean = true
453
)
454
455
// ... up to 22 parameter overloads
456
```
457
458
### Eager Singleton Bindings
459
460
Eager singleton bindings create their instance immediately when the DI container is built, not on first access.
461
462
```kotlin { .api }
463
/**
464
* Eager singleton that is created when the DI container is built
465
* @param T Return type of the eager singleton instance
466
*/
467
class EagerSingleton<T : Any> : DIBinding<Any, Unit, T>
468
469
/**
470
* Create an eager singleton binding
471
* @param creator Function that creates the instance immediately
472
* @return EagerSingleton binding instance
473
*/
474
fun <T : Any> DI.Builder.eagerSingleton(
475
creator: DirectDI.() -> T
476
): EagerSingleton<T>
477
478
/**
479
* Directly bind an eager singleton with convenience method
480
* @param tag Optional tag for the binding
481
* @param overrides Whether this binding may override existing bindings
482
* @param creator Function that creates the instance immediately
483
*/
484
fun <T : Any> DI.Builder.bindEagerSingleton(
485
tag: Any? = null,
486
overrides: Boolean? = null,
487
creator: DirectDI.() -> T
488
)
489
```
490
491
### Instance Bindings
492
493
Instance bindings store pre-created objects in the DI container for later retrieval.
494
495
```kotlin { .api }
496
/**
497
* Instance binding that stores a pre-created object
498
* @param T Type of the stored instance
499
*/
500
class InstanceBinding<T : Any> : DIBinding<Any, Unit, T>
501
502
/**
503
* Create an instance binding from a pre-created object
504
* @param instance The pre-created instance to store
505
* @return InstanceBinding that returns the stored instance
506
*/
507
fun <T : Any> DI.Builder.instance(instance: T): InstanceBinding<T>
508
509
/**
510
* Directly bind an instance with convenience method
511
* @param tag Optional tag for the binding
512
* @param overrides Whether this binding may override existing bindings
513
* @param creator Function that provides the instance to store
514
*/
515
fun <T : Any> DI.Builder.bindInstance(
516
tag: Any? = null,
517
overrides: Boolean? = null,
518
creator: () -> T
519
)
520
521
/**
522
* Bind a constant value (alias for bindInstance)
523
* @param tag Optional tag for the binding
524
* @param overrides Whether this binding may override existing bindings
525
* @param creator Function that provides the constant value
526
*/
527
fun <T : Any> DI.Builder.bindConstant(
528
tag: Any? = null,
529
overrides: Boolean? = null,
530
creator: () -> T
531
)
532
```
533
534
### Multiton Bindings
535
536
Multiton bindings create one instance per unique argument value, combining aspects of factory and singleton patterns.
537
538
```kotlin { .api }
539
/**
540
* Multiton binding that creates one instance per unique argument
541
* @param C Context type for scoped multitons
542
* @param A Argument type used as the multiton key
543
* @param T Return type of the multiton instances
544
*/
545
class Multiton<C : Any, A, T : Any> : DIBinding<C, A, T>
546
547
/**
548
* Create a multiton binding within a scoped BindBuilder context
549
* @param ref Reference type for instance storage
550
* @param sync Whether to synchronize access to multiton instances
551
* @param creator Function that creates instances for each unique argument
552
* @return Multiton binding instance
553
*/
554
fun <A, T : Any> DI.BindBuilder.WithScope<*>.multiton(
555
ref: RefMaker = MultitonReference,
556
sync: Boolean = true,
557
creator: BindingDI<*>.(A) -> T
558
): Multiton<*, A, T>
559
560
/**
561
* Directly bind a multiton with convenience method
562
* @param tag Optional tag for the binding
563
* @param overrides Whether this binding may override existing bindings
564
* @param sync Whether to synchronize access to multiton instances
565
* @param creator Function that creates instances for each unique argument
566
*/
567
fun <A, T : Any> DI.Builder.bindMultiton(
568
tag: Any? = null,
569
overrides: Boolean? = null,
570
sync: Boolean = true,
571
creator: DirectDI.(A) -> T
572
)
573
```
574
575
### Set Bindings
576
577
Set bindings allow multiple bindings for the same type, collecting them into a Set for retrieval.
578
579
```kotlin { .api }
580
/**
581
* Create a set binding and add elements to it
582
* @param tag Optional tag for the set binding
583
* @param overrides Whether this binding may override existing bindings
584
* @param type TypeToken for the set element type
585
* @param creator Block that adds bindings to the set
586
*/
587
fun <T : Any> DI.Builder.BindInSet(
588
tag: Any? = null,
589
overrides: Boolean? = null,
590
type: TypeToken<out T>,
591
creator: SetBinder<T>.() -> Unit
592
)
593
594
/**
595
* Add elements to an existing set binding
596
* @param tag Optional tag for the set binding
597
* @param overrides Whether this addition may override existing elements
598
* @param type TypeToken for the set element type
599
* @param creator Block that adds bindings to the set
600
*/
601
fun <T : Any> DI.Builder.InBindSet(
602
tag: Any? = null,
603
overrides: Boolean? = null,
604
type: TypeToken<out T>,
605
creator: SetBinder<T>.() -> Unit
606
)
607
608
/**
609
* Add a single binding to a set
610
* @param tag Optional tag for the set binding
611
* @param overrides Whether this addition may override existing elements
612
* @param binding The binding to add to the set
613
*/
614
fun <T : Any> DI.Builder.AddBindInSet(
615
tag: Any? = null,
616
overrides: Boolean? = null,
617
binding: DIBinding<*, *, T>
618
)
619
620
/**
621
* Set binder for adding multiple bindings to a set
622
*/
623
interface DI.Builder.SetBinder<T : Any> {
624
/**
625
* Add a binding to the set
626
* @param createBinding Function that creates the binding to add
627
*/
628
fun add(createBinding: () -> DIBinding<*, *, out T>)
629
630
/**
631
* Add a binding to both the set and the DI container
632
* @param tag Optional tag for the binding
633
* @param overrides Whether this binding may override existing bindings
634
* @param createBinding Function that creates the binding to add
635
*/
636
fun bind(
637
tag: Any? = null,
638
overrides: Boolean? = null,
639
createBinding: () -> DIBinding<*, *, out T>
640
)
641
}
642
```
643
644
**Usage Examples:**
645
646
```kotlin
647
val di = DI {
648
// Factory binding - new instance each time with argument
649
bind<UserRepository>() with factory { userId: String ->
650
UserRepositoryImpl(userId, instance())
651
}
652
653
// Provider binding - new instance each time, no arguments
654
bind<EmailService>() with provider {
655
EmailServiceImpl(instance(), instance())
656
}
657
658
// Singleton binding - one instance per container
659
bind<Database>() with singleton {
660
DatabaseImpl(constant("connectionString"))
661
}
662
663
// Eager singleton - created immediately when DI is built
664
bind<ConfigService>() with eagerSingleton {
665
ConfigServiceImpl().also { it.initialize() }
666
}
667
668
// Instance binding - pre-created object
669
bind<AppConfig>() with instance(AppConfig(debug = true))
670
671
// Multiton binding - one instance per unique argument
672
bind<Cache>() with multiton { cacheKey: String ->
673
InMemoryCache(cacheKey, instance())
674
}
675
676
// Constant binding with tag
677
constant("apiUrl") with "https://api.example.com"
678
constant("timeout") with 30_000L
679
680
// Set binding - multiple implementations
681
bindInSet<Plugin> {
682
add { provider { LoggingPlugin() } }
683
add { provider { MetricsPlugin() } }
684
add { provider { SecurityPlugin() } }
685
}
686
687
// Constructor injection with bindProviderOf
688
bindProviderOf(::UserServiceImpl) // Automatically injects constructor parameters
689
bindSingletonOf(::DatabaseConnectionPool)
690
691
// Using overrides
692
bind<Logger>(overrides = true) with singleton {
693
if (constant<Boolean>("debug")) ConsoleLogger() else FileLogger()
694
}
695
}
696
697
// Usage in classes
698
class UserController : DIAware {
699
override val di = di
700
701
private val userRepo: UserRepository by factory()
702
private val emailService: EmailService by provider()
703
private val database: Database by instance()
704
private val plugins: Set<Plugin> by instance()
705
706
fun createUser(userId: String) {
707
val repo = userRepo(userId) // Factory with argument
708
val email = emailService() // Provider creates new instance
709
// database is singleton, same instance each time
710
}
711
}
712
```