Dependency Injection experiment

Hi Oliver,

I guess I’m quite content to ditch autowiring at present - it’s not much overhead to be explicit if you use constructors to include dependencies (and it scales fairly well using named parameters).

In your example the container would just be the enclosing class and “wiring” is done explicitly via the constructor.

class Container {
  val someOtherBean by lazy { SomeOtherBean() }
  val someBean by lazy { SomeBean(someOtherBean) }
}

Or a less abstract example might be something like

class Container(val p: Properties) {
  val dataSource by lazy { DbConnectionPool(DataSource(p[“db.url”], p[“db.user”], p[“db.password”]) }
  val myDao by lazy { MyDao(dataSource) }
  val otherDao by lazy { OtherDao(dataSource) }
  val myService by lazy { transactional(MyService(myDao, otherDao)) }
  
  // Add support for proxies …  
  fun <T> proxy(obj: T, interceptors: Set<MethodInterceptor>): T …
  val transactionInterceptor = TransactionInterceptor()
  fun <T> transactional(obj: T, interceptors: T = proxy(obj, setOf(transactionInterceptor))

}

If you really want auto-wiring, following Andrey's suggestion you could do something like this:

class Container {
  val someOtherBean: SomeOtherBean by wired(this)
  val someBean: SomeBean by wired(this)   
}

where wired is a delagate that uses reflection on the instance (this) to look up the field type and do the auto wiring.

wired would probably also need to accept an optional class argument for the implementation class and you’d need some kind of qualifier mechanism to resolve ambiguities.

It might be nice if Kotlin’s PropertyMetadata included a reference to the enclosing object, then you could get rid of the the container reference - I imagine it could be a useful thing for delegates in general (although it might be considered leaky).

Cheers,
Andrew