27 June 2012

Dynamic dependency injection with Lift framework


Recently I have been working with scala and Lift.
Among many other features lift provide a convenient way to fordependency injection. Although cake pattern is the way to do dependency injection for scala users, it lakes in certain areas. Specially when working with multiple modules where abstraction and concrete implementation are in separate modules.
Lift Injector comes in handy in this context.
For example think of you have two module project core-logic and repository. core-logic is the place you want to keep all the business logic without infrastructure level details. core-logic will have some abstract  interfaces for repositories. e.g:-
trait UserRepository {
def createUserAccount(ua: UserAccount): Either[ErrorContext, UserAccount]
def findUserAccountByUsername(username: String): Either[ErrorContext, UserAccount]
}
repository is the place you want to keep the infrastructure (e.g:- db layer) level details.
class UserRepositoryImpl extends UserRepository {
      override def createUserAccount(ua: UserAccount): Either[ErrorContext, UserAccount] = {
      …
     }
}
Using static injection method it is difficult to inject this kind of dependency injection
object UserManagementDepInjector extends SimpleInjector {
}
With lift SimpleInjector you can register injections dynamically. This can be done at boot (if you are using life web framework)
class Boot {
   def boot {
      UserManagementDepInjector.registerInjection(() => {new UserRepositoryImpl()})(Manifest.classType(classOf[UserRepository]))
      …
   }
}
As in above we can register injections and Injector itself will handle injecting the correct concrete implementation.
class UserService {
   val userRepository: UserRepository = UserManagementDepInjector.inject[UserRepository].openTheBox
}
Need to mention that using of Box.openTheBox method may not be the recommended way. But I think in most practical cases application is not useful if that dependency is not available, so why bother !!!