Skip to content
Scala extensions for Google Guice
Scala Java
Branch: develop
Clone or download
This branch is 200 commits ahead, 1 commit behind benlings:master.

Latest commit

Latest commit 4a94b35 May 28, 2020

Files

Permalink
Type Name Latest commit message Commit time
Failed to load latest commit information.
project Bump version and simplify signing with gpg Dec 12, 2018
src
.gitignore Add 'idea' to gitignore May 23, 2014
.travis.yml Fix travis script May 28, 2020
CHANGELOG.md Bump version 4.2.5 Jun 22, 2019
LICENSE
NOTICE Update Copyright Dates. May 7, 2014
README.md Update Guice to 4.2.3 May 28, 2020
build.sbt Update Guice to 4.2.3 May 28, 2020

README.md

Scala extensions for Google Guice 4.2

Develop: Build Status

Getting Started

Add dependency

We currently support Scala 2.11, 2.12, 2.13

maven:
<dependency>
    <groupId>net.codingwell</groupId>
    <artifactId>scala-guice_2.13</artifactId>
    <version>4.2.7</version>
</dependency>
sbt:
"net.codingwell" %% "scala-guice" % "4.2.7"
gradle:
'net.codingwell:scala-guice_2.13:4.2.7'

Mixin

Mixin ScalaModule with your AbstractModule for rich scala magic (or ScalaPrivateModule with your PrivateModule):

import com.google.inject.{AbstractModule, PrivateModule}
import net.codingwell.scalaguice.{ScalaModule, ScalaPrivateModule}

class MyModule extends AbstractModule with ScalaModule {
  def configure(): Unit = {
    bind[Service].to[ServiceImpl].in[Singleton]
    bind[CreditCardPaymentService]
    bind[Bar[Foo]].to[FooBarImpl]
    bind[PaymentService].annotatedWith(Names.named("paypal")).to[CreditCardPaymentService]
  }
}

class MyPrivateModule extends PrivateModule with ScalaPrivateModule {
  def configure(): Unit = {
    bind[Foo].to[RealFoo]
    expose[Foo]

    install(new TransactionalBarModule())
    expose[Bar].annotatedWith[Transactional]

    bind[SomeImplementationDetail]
    install(new MoreImplementationDetailsModule())
  }
}

Inject

Wrap the injector in a ScalaInjector for even more rich scala magic:

import com.google.inject.Guice

object MyServer {
  def main(args: Array[String]) {
    val injector = Guice.createInjector(new MyModule(), new MyPrivateModule)

    import net.codingwell.scalaguice.InjectorExtensions._
    val service = injector.instance[Service]
    val foo = injector.instance[Foo]

    // Retrieve a Bar annotated with Transactional
    val bar = injector.instance[Bar, Transactional]

    // Retrieve a PaymentService annotated with a specific Annotation instance.
    val paymentService = injector.instance[PaymentService](Names.named("paypal"))
    ...
  }
}

Additional Features

Module Traits

class MyModule extends AbstractModule with ScalaModule
class MyPrivateModule extends PrivateModule with ScalaPrivateModule

This gives to access to scala style bindings:

bind[A].to[B]
bind[A].to(classOf[B])
bind[A].to(typeLiteral[B])
bind[A].toInstance("A")
bind[A].annotatedWith[Ann].to[B]
bind[A].annotatedWith( Names.named("name") ).to[B]
bind[A].annotatedWithName("name").to[B]
bind[A].toProvider[BProvider]
bind[A].toProvider[TypeProvider[B]]
bind[A[String]].to[B[String]]
bind[A].to[B].in[Singleton]

bindInterceptor[AOPI](methodMatcher = annotatedWith[AOP])

Multibinding

The ScalaMultibinder adds scala style multibindings:

class MyModule extends AbstractModule with ScalaModule {
  def configure(): Unit = {
    val stringMulti = ScalaMultibinder.newSetBinder[String](binder)
    stringMulti.addBinding.toInstance("A")

    val annotatedMulti = ScalaMultibinder.newSetBinder[A, Annotation](binder)
    annotatedMulti.addBinding.to[A]

    val namedMulti = ScalaMultibinder.newSetBinder[ServiceConfiguration](binder, Names.named("backend"))
    namedMulti.addBinding.toInstance(config.getAdminServiceConfiguration)
  }
}

And then they may be retrieved as immutable.Set[T]. (examples in order)

class StringThing @Inject() (strings: immutable.Set[String]) { ... }

class AThing @Inject() (@Annotation configs: immutable.Set[A]) { ... }

class Service @Inject() (@Names.named("backend") configs: immutable.Set[ServiceConfiguration]) { ... }

Generic Multibinding

trait Provider[T] {
  def provide: T
}

class StringProvider extends Provider[String] {
  override def provide = "Hello world!"
}

class IntProvider extends Provider[Int] {
  override def provide = 42
}
val multibinder = ScalaMultibinder.newSetBinder[Provider[_]](binder)

multibinder.addBinding.toInstance(new StringProvider)
multibinder.addBinding.toInstance(new IntProvider)

Provider[_] is actually translated to Provider[java.lang.Object]. So you need to use immutable.Set[Provider[Any]] and not immutable.Set[Provider[_]] :

class SomeClass @Inject() (providers: immutable.Set[Provider[Any]]) { ... }

OptionBinding

Newly available in Guice 4.0-beta5, we've got some support for OptionalBinder.

class MyModule extends AbstractModule with ScalaModule {
  def configure(): Unit = {
    val optBinder = ScalaOptionBinder.newOptionBinder[String](binder)
    optBinder.setDefault.toInstance("A")
    // To override the default binding (likely in another module):
    optBinder.setBinding.toInstance("B")

    val annotatedOptBinder = ScalaOptionBinder.newOptionBinder[A, Annotation](binder)
    annotatedOptBinder.setDefault.to[A]

    val namedOptBinder = ScalaOptionBinder.newOptionBinder[ServiceConfiguration](binder, Names.named("backend"))
    namedOptBinder.setBinding.toInstance(config.getAdminServiceConfiguration)
  }
}

And then they may be retrieved as Option[T], Option[Provider[T]], and Option[javax.inject.Provider[T]]. (examples in order)

class StringThing @Inject() (name: Option[String]) { ... }

class AThing @Inject() (@Annotation aProvider: Option[Provider[T]]) { ... }

class Service @Inject() (@Names.named("backend") configProvider: Option[javax.inject.Provider[ServiceConfiguration]]) { ... }

MapBinding

The ScalaMapBinder adds scala style mapbindings:

class MyModule extends AbstractModule with ScalaModule {
  def configure(): Unit = {
    val mBinder = ScalaMapBinder.newMapBinder[String, Int](binder)
    mBinder.addBinding("1").toInstance(1)
  }
}

And then may be retrieved as any of the following:

  • immutable.Map[K, V]
  • immutable.Map[K, Provider[V]]
  • immutable.Map[K, javax.inject.Provider[V]]

If you call mapBinder.permitDuplicates() on the binder then you may also inject:

  • immutable.Map[K, immutable.Set[V]]
  • immutable.Map[K, immutable.Set[Provider[V]]]

Interceptor Binding

bindInterceptor adds scala style interceptor binding

bindInterceptor(Matchers.any(), Matchers.annotatedWith(classOf[Logging]), new LoggingInterceptor())
bindInterceptor[LoggingInterceptor](methodMatcher = annotatedWith[Logging])

Gotchas

In Scala, the words override and with are reserved and must be escaped to be used.

Modules.`override`(new BaseModule).`with`(new TestModule)

And the stuff we forgot...

If you find a feature we support but don't mention here, submit an issue and we will add it.

If you find a feature we don't support but want, implement it and send us a pull request. Alternatively, you can file an issue and we may or may not get to it.

You can’t perform that action at this time.