Scaldi

Lightweight Scala Dependency Injection Library

Scaldi provides simple and elegant way to do dependency injection in Scala. By using expressive power of the Scala language it defines intuitive and idiomatic DSL for binding and injecting dependencies. It is very extensible library, so you can easily extend or customize almost any aspect of it. Some of the more unique Scaldi features are advanced module composition and conditional bindings which definitely will help you build all kinds of applications - from small command-line tools to big non-trivial web applications. Not to mention Scaldi also nicely integrates with Akka and Play.

Discover

Read the documentation and learn how you can use scaldi in your project.

Discuss

Have any ideas or questions? There are many places where you can share and discuss them with others.

Contribute

If you like the project and want to contribute, then there are plenty ways to do so. Any ideas, improvements or bugfixes are very welcome! Just fork it now and start implementing new cool stuff :)

Getting a Taste of Scaldi

Define Bindings

Scaldi provides nice DSL for defining the bindings

class UserModule extends Module {
  bind [MessageService] to new OfficialMessageService

  binding identifiedBy "greeting.official" to "Welcome"
}

Learn more about bindings

Inject Bindings

With neat DSL for injecting them

class OfficialMessageService(implicit inj: Injector)
          extends MessageService with Injectable {

  val officialGreeting =
    inject [String] (identified by "greeting.official")

  def getGreetMessage(name: String) =
    s"$officialGreeting, $name!"
}

Learn more about injection

Play Integration

Scaldi also comes with the play framework support. Start using scaldi in a play application is as simple as configuring application loader and modules in application.conf:

play.application.loader = scaldi.play.ScaldiApplicationLoader

play.modules.enabled += modules.MyModule
play.modules.enabled += scaldi.play.ControllerInjector

Play now uses scaldi for dependency injection. From now on you can use scaldi to inject/bind bindings in your controllers as classes:

class Application(implicit inj: Injector) extends Controller with Injectable {
  val messageService = inject [MessageService]

  def index = Action {
    Ok(views.html.index(messageService.getGreetMessage("Test User")))
  }
}

Learn more about play integration

Feature Highlights

Injector Composition

You can easily split bindings between different modules and then compose them together

def tokenModule = new Module {
  bind [Tokens] to new TokenRepo(db = inject [Database])
}

def dbModule = new Module {
  bind [Database] to new Riak
}

def appModule = tokenModule :: dbModule

Learn more about composition

Constructor Injection

Scaldi provides an injected macro, which will inject all constructor arguments for you:

class TokenRepo(db: Database, met: Metrics) extends Tokens

def tokenModule = new Module {
  bind [Tokens] to injected [TokenRepo]
}

You can even override injection mechanism on argument level:

def tokenModule = new Module {
  bind [Tokens] to injected [TokenRepo] (
    'met -> inject [Metrics] (identified by 'statsd))
}

Learn more about constructor injection

Binding Lifecycle

Bindings may have lifecycle

class MyModule extends Module {
  bind [ActorSystem] to
  ActorSystem("ScaldiExample") destroyWith (_.shutdown())

  bind [Database] to new Mongo initWith (_.start())
}

Learn more about lifecycle

Testing

You can override bindings in order to mock parts of the application

def mocksModule = new Module {
  bind [Database] to new InMemoryDb
}

implicit val testModule = mocksModule :: appModule

Learn more about testing

Conditions

Bindings may have conditions associated with them

class UserModule extends Module {
  bind [MessageService] when (inDevMode or inTestMode) to
    new SimpleMessageService

  bind [MessageService] when inProdMode to
    new OfficialMessageService
}

and it's pretty straightforward to define new conditions

def inDevMode(implicit inj: Injector) = {
  val mode = inject [Mode]
  Condition(mode == Dev)
}

Learn more about conditions

Generics

You can bind things like functions, lists or maps

binding identifiedBy "intAdder" to
  ((a: Int, b: Int) => a + b)

binding identifiedBy "mapping" to Map(
  "scala" -> "http://scala-lang.org",
  "play" -> "http://www.playframework.com",
  "akka" -> "http://akka.io"
)

and then inject them

val intAdder = inject [(Int, Int) => Int]
val mapping = inject [Map[String, String]]

JSR 330 Support

For seamless integration with other libraries or existing codebase.

def carModule = new Module {
  bind [Car] to annotated [Convertible]
  bind [Seat] identifiedBy qualifier [Drivers]
    to annotated [DriversSeat]
}

implicit val injector =
  carModule :: new OnDemandAnnotationInjector

val car = inject [Car]

Learn more about JSR 330 support

Extensibility

Extend almost any part of the library, including

  • Injector
  • Condition
  • Binding and BindingWithLifecycle
  • Identifier - create your own and define how they match

Some parts of the library are implemented as a type classes

  • CanCompose - defines how Injectors can be composed together
  • CanBeIdentifier

Akka Integration

With scaldi-akka you can inject ActorRefs and Props with injectActorProps and injectActorRef. Actors themselves can be defined in scaldi module.

class Receptionist(implicit inj: Injector) extends Actor with AkkaInjectable {
  val orderProcessorProps = injectActorProps [OrderProcessor]
  val priceCalculator = injectActorRef [PriceCalculator]

  def receive = {
    case PlaceOrder(userName, itemId, netAmount) =>
      val processor = context.actorOf(orderProcessorProps)
      // ...
  }
}

Learn more about akka integration

Getting Started

Just include scaldi dependency in the SBT build and you are ready to go:

libraryDependencies += "org.scaldi" %% "scaldi" % "0.5.8"

If you want to include scaldi into the play application, then scaldi-play would probably be more suitable for you

libraryDependencies += "org.scaldi" %% "scaldi-play" % "0.5.15"

Then you can just define application loader and your modules in the application.conf like this:

play.application.loader = scaldi.play.ScaldiApplicationLoader

play.modules.enabled += "modules.MyModule"
play.modules.enabled += "scaldi.play.ControllerInjector"

Play 2.3.x is still supported, you just need to use scaldi-play-23 instead:

          libraryDependencies += "org.scaldi" %% "scaldi-play-23" % "0.5.6"
          

For the akka applications, scaldi-akka is the way to go:

libraryDependencies += "org.scaldi" %% "scaldi-akka" % "0.5.8"

If you are integrating or migrating existing apps that use JSR 330 annotations, then scaldi-jsr330 is the right choice:

          libraryDependencies += "org.scaldi" %% "scaldi-jsr330" % "0.5.9"
          


After the initial setup you can read some documentation or look at scaldi presentation slides.

If you prefer more hands-on approach, then you may be interested in two example projects which you can play with: