0
# Direct Access
1
2
Immediate dependency retrieval without property delegation for cases requiring direct access to dependencies, providing synchronous resolution and explicit control over dependency lifecycle.
3
4
## Capabilities
5
6
### DirectDI Interface
7
8
Core interface for immediate dependency access without lazy initialization or property delegation overhead.
9
10
```kotlin { .api }
11
/**
12
* Base interface for classes that use direct dependency injection
13
*/
14
interface DirectDIAware {
15
/** Reference to the DirectDI instance */
16
val directDI: DirectDI
17
}
18
19
/**
20
* Base functionality for direct dependency access
21
*/
22
interface DirectDIBase : DirectDIAware {
23
/** The underlying container for dependency resolution */
24
val container: DIContainer
25
26
/** Get a regular lazy DI instance from this DirectDI */
27
val lazy: DI
28
29
/** Alias for lazy property */
30
val di: DI
31
32
/**
33
* Create a new DirectDI with different context
34
* @param context New context for scoped dependency resolution
35
* @return DirectDI instance with the specified context
36
*/
37
fun On(context: DIContext<*>): DirectDI
38
}
39
40
/**
41
* Platform-specific DirectDI interface for immediate dependency access
42
* Acts like a DI object but returns values instead of property delegates
43
*/
44
expect interface DirectDI : DirectDIBase
45
```
46
47
### Direct Instance Retrieval
48
49
Immediate retrieval of dependency instances without lazy initialization or caching overhead.
50
51
```kotlin { .api }
52
/**
53
* Get an instance of type T immediately
54
* @param type TypeToken representing the type to retrieve
55
* @param tag Optional tag for disambiguation
56
* @return Instance of type T
57
* @throws DI.NotFoundException if no binding is found
58
* @throws DI.DependencyLoopException if circular dependency is detected
59
*/
60
fun <T : Any> DirectDI.Instance(type: TypeToken<T>, tag: Any? = null): T
61
62
/**
63
* Get an instance with factory argument immediately
64
* @param argType TypeToken for the argument type
65
* @param type TypeToken for the return type
66
* @param tag Optional tag for disambiguation
67
* @param arg Argument value for the factory
68
* @return Instance of type T created with the argument
69
* @throws DI.NotFoundException if no binding is found
70
* @throws DI.DependencyLoopException if circular dependency is detected
71
*/
72
fun <A, T : Any> DirectDI.Instance(
73
argType: TypeToken<in A>,
74
type: TypeToken<T>,
75
tag: Any? = null,
76
arg: A
77
): T
78
79
/**
80
* Get an instance or null if not found
81
* @param type TypeToken representing the type to retrieve
82
* @param tag Optional tag for disambiguation
83
* @return Instance of type T or null if no binding found
84
* @throws DI.DependencyLoopException if circular dependency is detected
85
*/
86
fun <T : Any> DirectDI.InstanceOrNull(type: TypeToken<T>, tag: Any? = null): T?
87
88
/**
89
* Get an instance with factory argument or null if not found
90
* @param argType TypeToken for the argument type
91
* @param type TypeToken for the return type
92
* @param tag Optional tag for disambiguation
93
* @param arg Argument value for the factory
94
* @return Instance of type T or null if no binding found
95
* @throws DI.DependencyLoopException if circular dependency is detected
96
*/
97
fun <A, T : Any> DirectDI.InstanceOrNull(
98
argType: TypeToken<in A>,
99
type: TypeToken<T>,
100
tag: Any? = null,
101
arg: A
102
): T?
103
```
104
105
### Direct Provider Retrieval
106
107
Immediate retrieval of provider functions that create new instances when called.
108
109
```kotlin { .api }
110
/**
111
* Get a provider function immediately
112
* @param type TypeToken representing the type to provide
113
* @param tag Optional tag for disambiguation
114
* @return Provider function () -> T
115
* @throws DI.NotFoundException if no binding is found
116
* @throws DI.DependencyLoopException if circular dependency is detected
117
*/
118
fun <T : Any> DirectDI.Provider(type: TypeToken<T>, tag: Any? = null): () -> T
119
120
/**
121
* Get a provider curried from a factory with argument
122
* @param argType TypeToken for the argument type
123
* @param type TypeToken for the return type
124
* @param tag Optional tag for disambiguation
125
* @param arg Function providing the argument for currying
126
* @return Provider function () -> T
127
* @throws DI.NotFoundException if no binding is found
128
* @throws DI.DependencyLoopException if circular dependency is detected
129
*/
130
fun <A, T : Any> DirectDI.Provider(
131
argType: TypeToken<in A>,
132
type: TypeToken<T>,
133
tag: Any? = null,
134
arg: () -> A
135
): () -> T
136
137
/**
138
* Get a provider function or null if not found
139
* @param type TypeToken representing the type to provide
140
* @param tag Optional tag for disambiguation
141
* @return Provider function (() -> T)? or null if no binding found
142
* @throws DI.DependencyLoopException if circular dependency is detected
143
*/
144
fun <T : Any> DirectDI.ProviderOrNull(type: TypeToken<T>, tag: Any? = null): (() -> T)?
145
146
/**
147
* Get a provider curried from a factory or null if not found
148
* @param argType TypeToken for the argument type
149
* @param type TypeToken for the return type
150
* @param tag Optional tag for disambiguation
151
* @param arg Function providing the argument for currying
152
* @return Provider function (() -> T)? or null if no binding found
153
* @throws DI.DependencyLoopException if circular dependency is detected
154
*/
155
fun <A, T : Any> DirectDI.ProviderOrNull(
156
argType: TypeToken<in A>,
157
type: TypeToken<T>,
158
tag: Any? = null,
159
arg: () -> A
160
): (() -> T)?
161
```
162
163
### Direct Factory Retrieval
164
165
Immediate retrieval of factory functions that accept arguments and create instances.
166
167
```kotlin { .api }
168
/**
169
* Get a factory function immediately
170
* @param argType TypeToken for the argument type
171
* @param type TypeToken for the return type
172
* @param tag Optional tag for disambiguation
173
* @return Factory function (A) -> T
174
* @throws DI.NotFoundException if no binding is found
175
* @throws DI.DependencyLoopException if circular dependency is detected
176
*/
177
fun <A, T : Any> DirectDI.Factory(
178
argType: TypeToken<in A>,
179
type: TypeToken<T>,
180
tag: Any? = null
181
): (A) -> T
182
183
/**
184
* Get a factory function or null if not found
185
* @param argType TypeToken for the argument type
186
* @param type TypeToken for the return type
187
* @param tag Optional tag for disambiguation
188
* @return Factory function ((A) -> T)? or null if no binding found
189
* @throws DI.DependencyLoopException if circular dependency is detected
190
*/
191
fun <A, T : Any> DirectDI.FactoryOrNull(
192
argType: TypeToken<in A>,
193
type: TypeToken<T>,
194
tag: Any? = null
195
): ((A) -> T)?
196
```
197
198
### Reified Extension Methods
199
200
Type-safe extension methods for DirectDIAware that eliminate the need for explicit TypeToken parameters by using reified generics.
201
202
```kotlin { .api }
203
/**
204
* Get a factory function for type T with argument type A
205
* @param tag Optional tag for disambiguation
206
* @return Factory function that takes A and returns T
207
* @throws DI.NotFoundException if no binding is found
208
*/
209
inline fun <reified A : Any, reified T : Any> DirectDIAware.factory(tag: Any? = null): (A) -> T
210
211
/**
212
* Get a factory function for type T with argument type A, returning null if not found
213
* @param tag Optional tag for disambiguation
214
* @return Factory function or null if no binding is found
215
*/
216
inline fun <reified A : Any, reified T : Any> DirectDIAware.factoryOrNull(tag: Any? = null): ((A) -> T)?
217
218
/**
219
* Get a provider function for type T
220
* @param tag Optional tag for disambiguation
221
* @return Provider function that returns T
222
* @throws DI.NotFoundException if no binding is found
223
*/
224
inline fun <reified T : Any> DirectDIAware.provider(tag: Any? = null): () -> T
225
226
/**
227
* Get a provider function for type T with curried argument
228
* @param tag Optional tag for disambiguation
229
* @param arg Argument value to curry into the provider
230
* @return Provider function that returns T
231
*/
232
inline fun <reified A : Any, reified T : Any> DirectDIAware.provider(tag: Any? = null, arg: A): () -> T
233
234
/**
235
* Get a provider function for type T with typed argument
236
* @param tag Optional tag for disambiguation
237
* @param arg Typed argument value to curry into the provider
238
* @return Provider function that returns T
239
*/
240
inline fun <A, reified T : Any> DirectDIAware.provider(tag: Any? = null, arg: Typed<A>): () -> T
241
242
/**
243
* Get a provider function for type T with lazy argument
244
* @param tag Optional tag for disambiguation
245
* @param fArg Function that provides the argument value
246
* @return Provider function that returns T
247
*/
248
inline fun <reified A : Any, reified T : Any> DirectDIAware.provider(tag: Any? = null, noinline fArg: () -> A): () -> T
249
250
/**
251
* Get a provider function for type T, returning null if not found
252
* @param tag Optional tag for disambiguation
253
* @return Provider function or null if no binding is found
254
*/
255
inline fun <reified T : Any> DirectDIAware.providerOrNull(tag: Any? = null): (() -> T)?
256
257
/**
258
* Get a provider function for type T with curried argument, returning null if not found
259
* @param tag Optional tag for disambiguation
260
* @param arg Argument value to curry into the provider
261
* @return Provider function or null if no binding is found
262
*/
263
inline fun <reified A : Any, reified T : Any> DirectDIAware.providerOrNull(tag: Any? = null, arg: A): (() -> T)?
264
265
/**
266
* Get a provider function for type T with typed argument, returning null if not found
267
* @param tag Optional tag for disambiguation
268
* @param arg Typed argument value to curry into the provider
269
* @return Provider function or null if no binding is found
270
*/
271
inline fun <A, reified T : Any> DirectDIAware.providerOrNull(tag: Any? = null, arg: Typed<A>): (() -> T)?
272
273
/**
274
* Get a provider function for type T with lazy argument, returning null if not found
275
* @param tag Optional tag for disambiguation
276
* @param fArg Function that provides the argument value
277
* @return Provider function or null if no binding is found
278
*/
279
inline fun <reified A : Any, reified T : Any> DirectDIAware.providerOrNull(tag: Any? = null, noinline fArg: () -> A): (() -> T)?
280
281
/**
282
* Get an instance of type T immediately
283
* @param tag Optional tag for disambiguation
284
* @return Instance of type T
285
* @throws DI.NotFoundException if no binding is found
286
*/
287
inline fun <reified T : Any> DirectDIAware.instance(tag: Any? = null): T
288
289
/**
290
* Get an instance of type T with argument
291
* @param tag Optional tag for disambiguation
292
* @param arg Argument value for factory-based bindings
293
* @return Instance of type T
294
*/
295
inline fun <reified A : Any, reified T : Any> DirectDIAware.instance(tag: Any? = null, arg: A): T
296
297
/**
298
* Get an instance of type T with typed argument
299
* @param tag Optional tag for disambiguation
300
* @param arg Typed argument value for factory-based bindings
301
* @return Instance of type T
302
*/
303
inline fun <A, reified T : Any> DirectDIAware.instance(tag: Any? = null, arg: Typed<A>): T
304
305
/**
306
* Get an instance of type T, returning null if not found
307
* @param tag Optional tag for disambiguation
308
* @return Instance of type T or null if no binding is found
309
*/
310
inline fun <reified T : Any> DirectDIAware.instanceOrNull(tag: Any? = null): T?
311
312
/**
313
* Get an instance of type T with argument, returning null if not found
314
* @param tag Optional tag for disambiguation
315
* @param arg Argument value for factory-based bindings
316
* @return Instance of type T or null if no binding is found
317
*/
318
inline fun <reified A : Any, reified T : Any> DirectDIAware.instanceOrNull(tag: Any? = null, arg: A): T?
319
320
/**
321
* Get an instance of type T with typed argument, returning null if not found
322
* @param tag Optional tag for disambiguation
323
* @param arg Typed argument value for factory-based bindings
324
* @return Instance of type T or null if no binding is found
325
*/
326
inline fun <A, reified T : Any> DirectDIAware.instanceOrNull(tag: Any? = null, arg: Typed<A>): T?
327
328
/**
329
* Create a DirectDI with typed context
330
* @param context Context value for scoped dependencies
331
* @return DirectDI instance with the specified context
332
*/
333
inline fun <reified C : Any> DirectDIAware.on(context: C): DirectDI
334
```
335
336
### Constructor Injection (New Operator)
337
338
Advanced dependency injection for constructor parameters with automatic parameter resolution.
339
340
```kotlin { .api }
341
/**
342
* Create a new instance using constructor injection (no parameters)
343
* @param constructor Constructor function reference
344
* @return New instance with injected dependencies
345
*/
346
fun <T> DirectDIAware.new(constructor: () -> T): T
347
348
/**
349
* Create a new instance using constructor injection (1 parameter)
350
* @param constructor Constructor function reference
351
* @return New instance with injected dependencies
352
*/
353
fun <P1, T> DirectDIAware.new(constructor: (P1) -> T): T
354
355
/**
356
* Create a new instance using constructor injection (2 parameters)
357
* @param constructor Constructor function reference
358
* @return New instance with injected dependencies
359
*/
360
fun <P1, P2, T> DirectDIAware.new(constructor: (P1, P2) -> T): T
361
362
// ... up to 22 parameter overloads
363
364
/**
365
* Create a new instance within a DirectDI context
366
* @param creator Function that creates the instance using DirectDI
367
* @return Created instance
368
*/
369
inline fun <T> DirectDIAware.newInstance(creator: DirectDI.() -> T): T
370
```
371
372
### Context Management
373
374
Direct context switching and scoped dependency access for fine-grained control over dependency resolution contexts.
375
376
```kotlin { .api }
377
/**
378
* Create a DirectDI with typed context
379
* @param context Context value for scoped dependencies
380
* @return DirectDI instance with the specified context
381
*/
382
fun <C : Any> DirectDIAware.on(context: C): DirectDI
383
384
/**
385
* Access the lazy DI interface from DirectDIAware
386
*/
387
val DirectDIAware.lazy: DI
388
```
389
390
### Platform-Specific Extensions
391
392
Platform-specific DirectDI implementations with optimized method signatures and additional multi-binding support on JVM platform.
393
394
```kotlin { .api }
395
/**
396
* JVM-specific DirectDI methods for multi-binding support
397
* These methods are only available on the JVM platform
398
*/
399
400
/**
401
* Gets all factories that can return a T for the given argument type, return type and tag
402
* @param argType TypeToken for the argument type
403
* @param type TypeToken for the return type
404
* @param tag Optional tag for disambiguation
405
* @return List of all matching factory functions
406
*/
407
fun <A, T : Any> DirectDI.AllFactories(argType: TypeToken<in A>, type: TypeToken<T>, tag: Any? = null): List<(A) -> T>
408
409
/**
410
* Gets all providers that can return a T for the given type and tag
411
* @param type TypeToken for the return type
412
* @param tag Optional tag for disambiguation
413
* @return List of all matching provider functions
414
*/
415
fun <T : Any> DirectDI.AllProviders(type: TypeToken<T>, tag: Any? = null): List<() -> T>
416
417
/**
418
* Gets all providers that can return a T for the given type and tag, curried from factories
419
* @param argType TypeToken for the factory argument type
420
* @param type TypeToken for the return type
421
* @param tag Optional tag for disambiguation
422
* @param arg Function providing the argument value
423
* @return List of all matching provider functions with curried arguments
424
*/
425
fun <A, T : Any> DirectDI.AllProviders(argType: TypeToken<in A>, type: TypeToken<T>, tag: Any? = null, arg: () -> A): List<() -> T>
426
427
/**
428
* Gets all instances that can return a T for the given type and tag
429
* @param type TypeToken for the return type
430
* @param tag Optional tag for disambiguation
431
* @return List of all matching instances
432
*/
433
fun <T : Any> DirectDI.AllInstances(type: TypeToken<T>, tag: Any? = null): List<T>
434
435
/**
436
* Gets all instances that can return a T for the given type and tag, from factories
437
* @param argType TypeToken for the factory argument type
438
* @param type TypeToken for the return type
439
* @param tag Optional tag for disambiguation
440
* @param arg Argument value for the factories
441
* @return List of all matching instances created with the argument
442
*/
443
fun <A, T : Any> DirectDI.AllInstances(argType: TypeToken<in A>, type: TypeToken<T>, tag: Any? = null, arg: A): List<T>
444
445
/**
446
* Reified convenience methods for JVM multi-binding support
447
*/
448
inline fun <reified A : Any, reified T : Any> DirectDI.allFactories(tag: Any? = null): List<(A) -> T>
449
inline fun <reified T : Any> DirectDI.allProviders(tag: Any? = null): List<() -> T>
450
inline fun <reified A : Any, reified T : Any> DirectDI.allProviders(tag: Any? = null, noinline arg: () -> A): List<() -> T>
451
inline fun <reified T : Any> DirectDI.allInstances(tag: Any? = null): List<T>
452
inline fun <reified A : Any, reified T : Any> DirectDI.allInstances(tag: Any? = null, arg: A): List<T>
453
// and integration with Java reflection
454
}
455
456
// JavaScript-specific DirectDI implementation
457
// Located in src/jsBasedMain/kotlin/org/kodein/di/DirectDIJS.kt
458
actual interface DirectDI : DirectDIBase {
459
// JS-optimized implementations for browser and Node.js environments
460
}
461
```
462
463
**Usage Examples:**
464
465
```kotlin
466
// Basic DirectDI usage
467
class UserService(private val directDI: DirectDI) : DirectDIAware {
468
override val directDI = directDI
469
470
fun createUser(userData: UserData): User {
471
// Direct instance retrieval - immediate access
472
val repository = directDI.instance<UserRepository>()
473
val validator = directDI.instance<UserValidator>()
474
val emailService = directDI.instance<EmailService>("smtp")
475
476
// Factory with argument - immediate factory call
477
val logger = directDI.factory<String, Logger>()(this::class.simpleName!!)
478
479
// Provider for new instances each time
480
val sessionProvider = directDI.provider<UserSession>()
481
482
val user = User(userData)
483
repository.save(user)
484
emailService.sendWelcome(user)
485
logger.info("User created: ${user.id}")
486
487
return user
488
}
489
490
fun processUsers(userIds: List<String>) {
491
// Get factory once, use multiple times
492
val userFactory = directDI.factory<String, UserProcessor>()
493
494
userIds.forEach { userId ->
495
val processor = userFactory(userId) // Create processor for each user
496
processor.process()
497
}
498
}
499
}
500
501
// Constructor injection with new operator
502
class OrderService : DirectDIAware {
503
override val directDI: DirectDI = DI.direct {
504
bind<PaymentProcessor>() with singleton { StripePaymentProcessor() }
505
bind<InventoryService>() with singleton { InventoryServiceImpl() }
506
bind<EmailService>() with provider { EmailServiceImpl() }
507
bind<Logger>() with factory { name: String -> LoggerFactory.create(name) }
508
}
509
510
fun processOrder(orderData: OrderData) {
511
// Automatic constructor injection - finds dependencies automatically
512
val orderValidator = new(::OrderValidator) // Injects whatever OrderValidator needs
513
val paymentHandler = new(::PaymentHandler) // Injects PaymentProcessor, Logger, etc.
514
val fulfillmentService = new(::FulfillmentService) // Injects InventoryService, EmailService
515
516
orderValidator.validate(orderData)
517
val payment = paymentHandler.process(orderData.payment)
518
fulfillmentService.fulfill(orderData, payment)
519
}
520
}
521
522
// Context switching for scoped dependencies
523
class RequestHandler : DirectDIAware {
524
override val directDI: DirectDI = appDirectDI
525
526
fun handleRequest(request: HttpRequest) {
527
val requestContext = RequestContext(request.sessionId, request.userId)
528
529
// Switch to request-scoped context
530
val scopedDI = directDI.on(requestContext)
531
532
// These will use the request context for scoped singletons
533
val userSession = scopedDI.instance<UserSession>() // Scoped to this request
534
val requestLogger = scopedDI.instance<Logger>("request") // Request-specific logger
535
val permissions = scopedDI.instance<UserPermissions>() // Cached per request
536
537
// Process request with scoped dependencies
538
processWithContext(userSession, requestLogger, permissions, request)
539
}
540
}
541
542
// Mixing direct and lazy access patterns
543
class HybridService : DIAware, DirectDIAware {
544
override val di: DI = appDI
545
override val directDI: DirectDI = appDI.direct
546
547
// Some dependencies as lazy properties (rarely accessed)
548
private val configService: ConfigService by instance()
549
private val metricsCollector: MetricsCollector by instance()
550
551
fun processData(data: List<DataItem>) {
552
// Direct access for per-operation dependencies
553
val processor = directDI.instance<DataProcessor>()
554
val validator = directDI.instance<DataValidator>()
555
556
// Lazy properties accessed only when needed
557
val config = configService.getProcessingConfig()
558
559
data.forEach { item ->
560
// New processor instance for each item if needed
561
val itemProcessor = directDI.provider<ItemProcessor>()()
562
itemProcessor.process(item, config)
563
564
// Record metrics (lazy property)
565
metricsCollector.record("item_processed", item.type)
566
}
567
}
568
}
569
570
// Error handling with direct access
571
class RobustService : DirectDIAware {
572
override val directDI: DirectDI = serviceDirectDI
573
574
fun robustOperation() {
575
try {
576
val primaryService = directDI.instance<PrimaryService>()
577
primaryService.execute()
578
} catch (e: DI.NotFoundException) {
579
// Fallback to secondary service
580
val fallbackService = directDI.instanceOrNull<FallbackService>()
581
if (fallbackService != null) {
582
fallbackService.execute()
583
} else {
584
throw ServiceUnavailableException("No service available", e)
585
}
586
} catch (e: DI.DependencyLoopException) {
587
val emergencyService = new(::EmergencyService) // Bypass DI for emergency
588
emergencyService.handleEmergency()
589
}
590
}
591
}
592
```