or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

advanced-features.mdbinding-dsl.mdcontainer-configuration.mddirect-access.mdindex.mdlazy-property-delegation.mdscoping-and-context.md

direct-access.mddocs/

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

```